changeset 7096:63aae28fa10f streaming

reviewing documentation of new options
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 13 Aug 2026 13:18:38 +0000
parents 1e78972b48fa
children 6d624dfcad3e
files OrthancFramework/Sources/DataSource/DataSourceSequentialReader.h OrthancFramework/Sources/DataSource/DicomSequentialReader.h OrthancServer/Resources/AdvancedConfiguration.json OrthancServer/Resources/Configuration.json TODO
diffstat 5 files changed, 60 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancFramework/Sources/DataSource/DataSourceSequentialReader.h	Thu Aug 13 12:01:37 2026 +0000
+++ b/OrthancFramework/Sources/DataSource/DataSourceSequentialReader.h	Thu Aug 13 13:18:38 2026 +0000
@@ -127,7 +127,7 @@
     DataSourceSequentialReader(const boost::shared_ptr<IExecutorService>& executor,
                                const boost::shared_ptr<DataSourceReader>& reader,
                                IValueDisconnector* disconnector /* takes ownership */,
-                               unsigned int windowSize /* number of elements in the sliding window */,
+                               unsigned int windowSize /* maximum number of elements in the sliding window */,
                                uint64_t windowCapacity /* if 0, memory usage is only controlled by the size of the sliding window */);
 
     ~DataSourceSequentialReader();
--- a/OrthancFramework/Sources/DataSource/DicomSequentialReader.h	Thu Aug 13 12:01:37 2026 +0000
+++ b/OrthancFramework/Sources/DataSource/DicomSequentialReader.h	Thu Aug 13 13:18:38 2026 +0000
@@ -117,8 +117,8 @@
               const boost::shared_ptr<DataSourceReader>& storageAreaReader,
               const boost::shared_ptr<DataSourceReader>& dicomReader,
               const boost::shared_ptr<DataSourceReader>& transcoderReader,
-              unsigned int windowSize,
-              uint64_t windowCapacity);
+              unsigned int windowSize /* maximum number of elements in the sliding window */,
+              uint64_t windowCapacity /* if 0, memory usage is only controlled by the size of the sliding window */);
 
       const boost::shared_ptr<IExecutorService>& GetExecutorService() const
       {
--- a/OrthancServer/Resources/AdvancedConfiguration.json	Thu Aug 13 12:01:37 2026 +0000
+++ b/OrthancServer/Resources/AdvancedConfiguration.json	Thu Aug 13 13:18:38 2026 +0000
@@ -291,9 +291,6 @@
 
   /**
    * Performance-related options
-   *
-   * TODO-Streaming: add a page in the book: performance: fine tuning:
-   * limiting memory + increasing the number of threads
    **/
 
   // Defines the number of threads that are used to execute each type of
@@ -327,7 +324,7 @@
   // Default number of loader threads to use in jobs that read multiple files
   // from the storage area when executing some tasks, including:
   // - generating archive/media,
-  // - executing a C-Store,
+  // - executing a C-STORE,
   // - transmitting resources through Orthanc peering.
   // A value of 0 and 1 are equivalent: a single thread is used.
   // A value > 1 is meaningful only if the storage is a distributed network storage
@@ -384,33 +381,45 @@
   // cache. (new in Orthanc 1.13.0)
   "TranscoderCacheSize" : 256,
 
-  // Total number of threads that are used to provide DICOM files
-  // sequentially (currently used in Archive jobs, C-Store, and C-Get).
-  // Each time such a job needs to get a DICOM file content, it
-  // requests it from a sequential DICOM reader that will itself use a
-  // storage loader thread. Therefore, by default, the value of this
-  // configuration is identical to "StorageLoaderThreadsCount". You
-  // should monitor the "orthanc_seq_reader_available_threads" metrics
-  // to determine the optimal value for your setup and usage. (new in
-  // Orthanc 1.13.0)
+  // Number of threads for the sequential access to DICOM
+  // instances. When a thread in Orthanc needs a set of DICOM
+  // instances in a predefined order, it cannot rely directly on
+  // loader threads, which may provide the instances out of
+  // order. This is notably the case for archive jobs, C-STORE SCU
+  // connections, and C-GET SCP and C-MOVE SCP handlers. In such
+  // situations, Orthanc uses a sliding-window buffer that is
+  // populated by a set of threads calling the out-of-order loader
+  // threads. These preloading threads are part of a pool that is
+  // global to Orthanc. The threads are paused if the buffer grows too
+  // large before the calling thread consumes the instances. By
+  // default, this option has the same value as
+  // "StorageLoaderThreadsCount". You should monitor the
+  // "orthanc_seq_reader_available_threads" metrics to determine the
+  // optimal value for your setup and usage. (new in Orthanc 1.13.0)
   // "SequentialDicomReaderThreadsCount" : 4,
 
-  // Number of files each sequential DICOM reader is allowed to buffer
-  // in advance before it is consumed by the related job.
-  // This is kind of equivalent to the older "LoaderThreads" configuration
-  // but, furthermore, you must make sure that there are enough "StorageLoaderThreadsCount"
-  // and "SequentialDicomReaderThreadsCount" for each job ->
-  // "StorageLoaderThreadsCount" should be larger than "ConcurrentJobs" * "SequentialDicomReaderWindowSize"
-  // Together with "SequentialDicomReaderWindowCapacity", this also defines the amount of memory that is
-  // used by each job that required a SequentialDicomReader.
-  // By default, the value of this configuration is the same as "LoaderThreadsCount". (new in Orthanc 1.13.0)
+  // Each thread that accesses DICOM instances in sequential order
+  // creates a local sliding-window buffer that is preloaded by the
+  // global thread pool (cf. "SequentialDicomReaderThreadsCount").
+  // This configuration option specifies the maximum number of DICOM
+  // instances that can be preloaded before they are consumed by the
+  // calling thread. Together with
+  // "SequentialDicomReaderWindowCapacity", this option determines the
+  // amount of memory used by each calling thread that requires
+  // sequential access to DICOM instances. This is roughly equivalent
+  // to the older "LoaderThreads" configuration: By default, this
+  // option is therefore set to the same value as "LoaderThreads", if
+  // the latter is available. (new in Orthanc 1.13.0)
   "SequentialDicomReaderWindowSize" : 4,
 
-  // Peak amount of RAM (in MB) that can be allocated by each
-  // sequential DICOM reader. The sequential DICOM reader pauses
-  // buffering as soon as one of the "SequentialDicomReaderWindowSize"
-  // or "SequentialDicomReaderWindowCapacity" limit is reached. Note
-  // that this limit can be exceeded when a single file is larger than
-  // this option. (new in Orthanc 1.13.0)
-  "SequentialDicomReaderWindowCapacity" : 64
+  // Maximum amount of RAM (in MB) allocated to each local
+  // sliding-window buffer for each thread accessing a set of DICOM
+  // instances in sequential order (see
+  // "SequentialDicomReaderThreadsCount"). The global thread pool
+  // pauses preloading as soon as either the
+  // "SequentialDicomReaderWindowSize" or
+  // "SequentialDicomReaderWindowCapacity" limit is reached. Note that
+  // this limit can be exceeded when a single file is larger than the
+  // value specified by this option. (new in Orthanc 1.13.0)
+  "SequentialDicomReaderWindowCapacity" : 128
 }
--- a/OrthancServer/Resources/Configuration.json	Thu Aug 13 12:01:37 2026 +0000
+++ b/OrthancServer/Resources/Configuration.json	Thu Aug 13 13:18:38 2026 +0000
@@ -37,9 +37,9 @@
   // Action to take when the maximum storage is reached.
   // By default, the patients are recycled ("Recycle" mode).
   // In "Reject" mode, the sender will receive a 0xA700 DIMSE status code
-  // if the instance was sent through C-Store, a 507 HTTP status code
+  // if the instance was sent through C-STORE, a 507 HTTP status code
   // if using the REST API and a 0xA700 Failure reason when using
-  // DICOMweb Stow-RS.
+  // DICOMweb STOW-RS.
   // Note: this value is taken into account only if you have set 
   // a MaximumStorageSize != 0 or a MaximumPatientCount != 0
   // Allowed values: "Recycle", "Reject"
@@ -483,9 +483,9 @@
   // be run when Orthanc is acting as SCP. 
   // Note: This is not limiting the number of concurrent connections
   // but the number of concurrent DICOM operations.
-  // For instance, with a single thread, if a C-Find request is received during
-  // e.g. the transcoding of an incoming C-Store, the C-Find will
-  // be processed only at the end of the C-Store operation but both
+  // For instance, with a single thread, if a C-FIND request is received during
+  // e.g. the transcoding of an incoming C-STORE, the C-FIND will
+  // be processed only at the end of the C-STORE operation but both
   // DICOM associations will remain active.
   // (new in Orthanc 1.10.0, before this version, the value was fixed to 4)
   "DicomThreadsCount" : 4,
--- a/TODO	Thu Aug 13 12:01:37 2026 +0000
+++ b/TODO	Thu Aug 13 13:18:38 2026 +0000
@@ -74,6 +74,18 @@
 * Unable to cancel an ArchiveJob when Orthanc does not have access to the storage anymore.
   (To reproduce: remove the cable while downloading a study from S3)
 
+* TODO-Streaming: This guideline was removed from
+  "AdvancedConfiguration.json" in the description of option
+  "SequentialDicomReaderWindowSize", as it might be incorrect in some
+  situations:
+
+  // This is kind of equivalent to the older "LoaderThreads" configuration
+  // but, furthermore, you must make sure that there are enough "StorageLoaderThreadsCount"
+  // and "SequentialDicomReaderThreadsCount" for each job ->
+  // "StorageLoaderThreadsCount" should be larger than "ConcurrentJobs" * "SequentialDicomReaderWindowSize"
+  // Together with "SequentialDicomReaderWindowCapacity", this also defines the amount of memory that is
+  // used by each job that required a SequentialDicomReader.
+
 
 ============================
 Documentation (Orthanc Book)
@@ -102,6 +114,8 @@
 * Discuss HL7 in a dedicated page:
   https://groups.google.com/d/msg/orthanc-users/4dt4992O0lQ/opTjTFU2BgAJ
   https://groups.google.com/g/orthanc-users/c/Spjtcj9vSPo/m/ktUArWxUDQAJ
+* TODO-Streaming: add a page in the book about performance (fine
+  tuning limiting memory + increasing the number of threads)
 
 
 ================