view Sphinx/source/plugins/advanced-storage.rst @ 1167:84e0b7ec5a1b

advanced storage + pg 8
author Alain Mazy <am@orthanc.team>
date Mon, 16 Jun 2025 21:50:32 +0200
parents
children 6a592d137f23
line wrap: on
line source

.. _advanced-storage:


Advanced storage plugin
=======================

.. contents::

This **official plugin** extends Orthanc with an advanced
storage mechanism:

- It enables customization of the structure of the Orthanc storage.
- It supports multiple storages.
- It supports indexing an existing storage - replacing the :ref:`Indexer <indexer>` plugin.
- It supports delayed deletion - replacing the  :ref:`Delayed deletion plugin <delayed-deletion-plugin>` plugin

Restrictions
------------

.. warning:: 
  This plugin only works with either the default SQLite database (from Orthanc 1.12.8) 
  or the PostgreSQL Index plugin (from version 8.0).


How to get it ?
---------------

The source code is available on `Github <https://github.com/orthanc-server/orthanc-advanced-storage/>`__.

Binaries are included in:

- The `orthancteam/orthanc Docker image <https://hub.docker.com/r/orthancteam/orthanc>`__
- The `Windows Installer <https://www.orthanc-server.com/download-windows.php>`__
- The `MacOS packages <https://www.orthanc-server.com/static.php?page=download-mac>`__

Release notes are available `here <https://github.com/orthanc-server/orthanc-advanced-storage/blob/master/release-notes.md>`__.

Compilation instructions are available below.


Usage
-----

.. highlight:: json

Once Orthanc is installed, you must change the :ref:`configuration file
<configuration>` to tell Orthanc where it can find the plugin: This is
done by properly modifying the ``Plugins`` option. You could for
instance use the following configuration file::

  {
    "Name" : "MyOrthanc",
    [...]
    "Plugins" : [
      "/home/user/OrthancAuthorization/Build/libAdvancedStorage.so"
    ],
    "AdvancedStorage" : {
      "Enable": true,

      // .. see below "configuration section"
    }
  }

Orthanc must of course be restarted after the modification of its
configuration file.


Configuration
-------------

A full description of all configuration options is available directly
in the source code `default configuration file <https://github.com/orthanc-server/orthanc-advanced-storage/blob/master/Plugin/Configuration.json>`__.


Multiple storages
-----------------

If your current storage gets full, you may configuration the plugin
to use another disk to store newly received DICOM files::

  {
    "StorageDirectory": "/var/lib/orthanc/db/",
    ...
    "AdvancedStorage": {
      "Enable": true,
      "MultipleStorages": {
        "Storages": {
          "ext1": "/mnt/disk1/orthanc",
          "ext2": "/mnt/disk2/orthanc",
        },
        "CurrentWriteStorage": "ext1"
    }
  }

E.g., with the above configuration, Orthanc might have ingested DICOM
files a long time ago.  These files are still stored in ``/var/lib/orthanc/db/``
(the main ``StorageDirectory``).  The advanced storage plugin will
still be able to read files from this directory.

Then, the advanced storage plugin has been configured to use 2 extra disks
whose ids are ``ext1`` and ``ext2``.  These identifiers can never change since
they are stored in DB for each file.

The ``CurrentWriteStorage`` configuration defines where the new received
files are stored.

Note that, if one of the disks gets full, you'll have to switch the ``CurrentWriteStorage``
configuration manually.


Customizing paths
-----------------

By default, in Orthanc, each file is
automatically associated with an `universally unique identifier (UUID)
<https://en.wikipedia.org/wiki/Universally_unique_identifier>`__ and files are
stored in a 3-level hierarchy of directories; the
first two hexadecimal characters of the UUID give the first-level
folder, and the two next characters give the second-level folder (e.g.: ``/var/lib/orthanc/db/5f/39/5f3936ea-95b6-4ad9-b0f1-4075be3e52d0``).  
This structure is machine friendly but is not convenient to browse for a human.

One of the great feature of the advanced storage plugin is its ability to
customize the storage structure.  The ``NamingScheme`` configuration enables full
customization of the storage structure by using :ref:`DICOM Tags <main-dicom-tags>` or :ref:`Orthanc identifiers 
<orthanc-ids>` from the DICOM instance.

E.g., a ``NamingScheme`` of ``{PatientID} - {PatientName}/{StudyDate} - {StudyDescription}/{SeriesNumber}/{pad6(InstanceNumber)}-{UUID}{.ext}``
will produce paths like ``1234 - WHO^JOHN/20241102 - HEAD SCAN/100/000007-5f3936ea-95b6-4ad9-b0f1-4075be3e52d0.dcm``.

Check the `configuration file <https://github.com/orthanc-server/orthanc-advanced-storage/blob/master/Plugin/Configuration.json>`__ for 
a full description of the keywords that can be used in the ``NamingScheme``.

To prevent files from being overwritten, it is very important that their path is unique !
Therefore, your NamingScheme must always include:

- either the file ``{UUID}``
- or, if you have not set ``"OverwriteInstances"`` to true, at least:
    
  - a patient identifier ``{PatientID}`` or ``{OrthancPatientID}``,
  - a study identifier ``{StudyInstanceUID}`` or ``{OrthancStudyID}``,
  - a series identifier ``{SeriesInstanceUID}`` or ``{OrthancSeriesID}``,
  - an instance identifier ``{SOPInstanceUID}`` or ``{OrthancInstanceID}``

The ``NamingScheme`` defines a **relative** path to either the ``"StorageDirectory"`` of Orthanc or one of
the ``"MultipleStorages"`` of this plugin.
    
The relative path generated from the ``NamingScheme`` is stored in the SQL DB.  Therefore, you may change the
``NamingScheme`` at any time and you'll still be able to access previously saved files.


Indexer mode
------------

This plugin can actually also replace the :ref:`Folder Indexer plugin<indexer>`.  The
Indexer plugin needed a separate SQLite DB which made it impossible to use with multiple
Orthanc instances or uncomfortable to use together with the PostgreSQL plugin.

The advanced-storage implements the same features as the Indexer plugin without requiring
a separate DB.  Everything is stored in the Orthanc main Database.

The ``Indexer mode`` has its own configuration::

  {
    "StorageDirectory": "/var/lib/orthanc/db/",
    ...
    "AdvancedStorage": {
      "Enable": true,
      "Indexer": {
        "Enable": true,
        "Folders": [ "/tmp/dicom-files" ],
        ...
        "TakeOwnership": false
    }
  }

Check the `configuration file <https://github.com/orthanc-server/orthanc-advanced-storage/blob/master/Plugin/Configuration.json>`__ for 
all the ``Indexer mode`` configurations.

If you set ``TakeOwnership`` to false (default), the ``Indexer mode`` will have the
exact same behavior as the Indexer plugin.  Orthanc will not own the indexed files
and will therefore not delete the files if you delete the related resources in Orthanc.

If you set ``TakeOwnership`` to true, all indexed files will belong to Orthanc
and will therefore delete the files if you delete the related resources in Orthanc.

Setting ``TakeOwnership`` to true is useful e.g. when you have been using Orthanc with
the default SQLite DB and you wish to switch to PostgreSQL.  Orthanc will then be able
to *adopt* the DICOM files from the previous Orthanc installation.  TODO: check this sample setup TODO


Delayed deletion mode
---------------------

This plugin can actually also replace the :ref:`Delayed deletion plugin<delayed-deletion-plugin>`.  The
Delayed deletion plugin needed a separate SQLite DB which made it impossible to use with multiple
Orthanc instances or uncomfortable to use together with the PostgreSQL plugin.

The advanced-storage implements the same features as the Delayed deletion plugin without requiring
a separate DB.  Everything is stored in the Orthanc main Database.

The ``Delayed deletion mode`` has its own configuration::

  {
    "StorageDirectory": "/var/lib/orthanc/db/",
    ...
    "AdvancedStorage": {
      "Enable": true,
      "DelayedDeletion": {
        "Enable": true,
        ...
    }
  }

Check the `configuration file <https://github.com/orthanc-server/orthanc-advanced-storage/blob/master/Plugin/Configuration.json>`__ for 
all the ``Delayed deletion mode`` configurations.



REST API extensions
-------------------

This plugin brings in a few new API routes:

**adopt-instance** to adopt an instance that is outside the storage.  This is equivalent to the
Indexer mode adopting an instance::

  $ curl http://localhost:8042/plugins/advances-storage/adopt-instance -d @- << EOF
  {
    "Path" : "/tmp/my-dicom-file.dcm",
    "TakeOwnership" : false
  }
  EOF

**abandon-instance** to remove an adopted instance (if Orthanc is not the owner of the instance).  
This is equivalent to the Indexer mode abandoning an instance e.g. the indexed file has been deleted::

  $ curl http://localhost:8042/plugins/advances-storage/abandon-instance -d @- << EOF
  {
    "Path" : "/tmp/my-dicom-file.dcm"
  }
  EOF

**move-storage** to move a resource from a storage to another one.  Note: it does not recompute the relative path 
but only change the base path (aka ``StorageId``)::

  $ curl http://localhost:8044/plugins/advanced-storage/move-storage -d @- << EOF
  {
    "Resources": ["ca58b590-8a115ed5-906f7f21-c7af8058-2637f722"],
    "TargetStorageId": "ext2"
  }
  EOF


The plugin now provides extra information in the **../attachments/info** routes.  E.g.::

  $ curl http://localhost:8042/instances/ca58b590-8a115ed5-906f7f21-c7af8058-2637f722/attachments/dicom/info 

  will return these new fields

  {
    ...
    "IsOwnedByOrthanc" : true,
    "Path" : "1234 - WHO^JOHN/20241102 - HEAD SCAN/100/000007-5f3936ea-95b6-4ad9-b0f1-4075be3e52d0.dcm",
    "StorageId" : "ext1"
  }


The plugin also provides its status in this route **/plugins/advanced-storage/status**.  E.g.::

  $ curl http://localhost:8042/plugins/advanced-storage/status 

  will return 

  {
    "DelayedDeletionIsActive": true,
    "FilesPendingDeletion": 123,
    "IndexerIsActive": true
  }


Compilation
-----------

.. highlight:: bash

The procedure to compile this plugin is similar of that for the
:ref:`core of Orthanc <binaries>`. The following commands should work
for most UNIX-like distribution (including GNU/Linux)::

  $ mkdir Build
  $ cd Build
  $ cmake .. -DSTATIC_BUILD=ON -DCMAKE_BUILD_TYPE=Release
  $ make

The compilation will produce a shared library ``AdvancedStorage``
that contains the plugin.