changeset 1136:42581a6182c8 broker

reactivation of the cache of parsed DICOM files
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 06 Nov 2019 17:54:14 +0100
parents a0a33e5ea5bb
children cc029987b6dc
files Framework/Oracle/GenericOracleRunner.cpp Framework/Toolbox/ParsedDicomFileCache.cpp Framework/Toolbox/ParsedDicomFileCache.h
diffstat 3 files changed, 147 insertions(+), 76 deletions(-) [+]
line wrap: on
line diff
--- a/Framework/Oracle/GenericOracleRunner.cpp	Wed Nov 06 17:34:58 2019 +0100
+++ b/Framework/Oracle/GenericOracleRunner.cpp	Wed Nov 06 17:54:14 2019 +0100
@@ -238,64 +238,143 @@
 
 
 #if ORTHANC_ENABLE_DCMTK == 1
-  static void RunInternal(boost::weak_ptr<IObserver> receiver,
-                          IMessageEmitter& emitter,
-                          const std::string& root,
-                          const ParseDicomFileCommand& command)
+  namespace
   {
-    std::string path = GetPath(root, command.GetPath());
-
-    if (!Orthanc::SystemToolbox::IsRegularFile(path))
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentFile);
-    }
-
-    uint64_t fileSize = Orthanc::SystemToolbox::GetFileSize(path);
-
-    // Check for 32bit systems
-    if (fileSize != static_cast<uint64_t>(static_cast<size_t>(fileSize)))
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_NotEnoughMemory);
-    }
-
-    DcmFileFormat dicom;
-    bool ok;
-
-    if (command.IsPixelDataIncluded())
-    {
-      ok = dicom.loadFile(path.c_str()).good();
-    }
-    else
+    class IDicomHandler : public boost::noncopyable
     {
-#if DCMTK_VERSION_NUMBER >= 362
-      // NB : We could stop at (0x3007, 0x0000) instead of
-      // DCM_PixelData, cf. the Orthanc::DICOM_TAG_* constants
+    public:
+      virtual ~IDicomHandler()
+      {
+      }
+
+      virtual void Handle(Orthanc::ParsedDicomFile* dicom,
+                          const ParseDicomFileCommand& command,
+                          uint64_t fileSize) = 0;
+
+      static void Apply(IDicomHandler& handler,
+                        const std::string& root,
+                        const ParseDicomFileCommand& command)
+      {
+        std::string path = GetPath(root, command.GetPath());
 
-      static const DcmTagKey STOP = DCM_PixelData;
-      //static const DcmTagKey STOP(0x3007, 0x0000);
+        if (!Orthanc::SystemToolbox::IsRegularFile(path))
+        {
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentFile);
+        }
+
+        uint64_t fileSize = Orthanc::SystemToolbox::GetFileSize(path);
+
+        // Check for 32bit systems
+        if (fileSize != static_cast<uint64_t>(static_cast<size_t>(fileSize)))
+        {
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_NotEnoughMemory);
+        }
+
+        DcmFileFormat dicom;
+        bool ok;
 
-      ok = dicom.loadFileUntilTag(path.c_str(), EXS_Unknown, EGL_noChange,
-                                  DCM_MaxReadLength, ERM_autoDetect, STOP).good();
+        if (command.IsPixelDataIncluded())
+        {
+          ok = dicom.loadFile(path.c_str()).good();
+        }
+        else
+        {
+#if DCMTK_VERSION_NUMBER >= 362
+          // NB : We could stop at (0x3007, 0x0000) instead of
+          // DCM_PixelData, cf. the Orthanc::DICOM_TAG_* constants
+
+          static const DcmTagKey STOP = DCM_PixelData;
+          //static const DcmTagKey STOP(0x3007, 0x0000);
+
+          ok = dicom.loadFileUntilTag(path.c_str(), EXS_Unknown, EGL_noChange,
+                                      DCM_MaxReadLength, ERM_autoDetect, STOP).good();
 #else
-      // The primitive "loadFileUntilTag" was introduced in DCMTK 3.6.2
-      ok = dicom.loadFile(path.c_str()).good();
+          // The primitive "loadFileUntilTag" was introduced in DCMTK 3.6.2
+          ok = dicom.loadFile(path.c_str()).good();
 #endif
-    }
+        }
+
+        printf("Reading %s\n", path.c_str());
+
+        if (ok)
+        {
+          handler.Handle(new Orthanc::ParsedDicomFile(dicom), command, fileSize);
+        }
+        else
+        {
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
+                                          "Cannot parse file: " + path);
+        }
+      }
+    };
+
 
-    printf("Reading %s\n", path.c_str());
+    class DicomHandlerWithoutCache : public IDicomHandler
+    {
+    private:
+      boost::weak_ptr<IObserver> receiver_;
+      IMessageEmitter&           emitter_;
+      
+    public:
+      DicomHandlerWithoutCache(boost::weak_ptr<IObserver> receiver,
+                               IMessageEmitter& emitter) :
+        receiver_(receiver),
+        emitter_(emitter)
+      {
+      }        
+      
+      virtual void Handle(Orthanc::ParsedDicomFile* dicom,
+                          const ParseDicomFileCommand& command,
+                          uint64_t fileSize)
+      {
+        std::auto_ptr<Orthanc::ParsedDicomFile> parsed(dicom);
 
-    if (ok)
+        ParseDicomFileCommand::SuccessMessage message
+          (command, *parsed, static_cast<size_t>(fileSize), command.IsPixelDataIncluded());
+        emitter_.EmitMessage(receiver_, message);
+      }
+    };
+
+
+    class DicomHandlerWithCache : public IDicomHandler
     {
-      Orthanc::ParsedDicomFile parsed(dicom);
-      ParseDicomFileCommand::SuccessMessage message
-        (command, parsed, static_cast<size_t>(fileSize), command.IsPixelDataIncluded());
-      emitter.EmitMessage(receiver, message);
-    }
-    else
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
-                                      "Cannot parse file: " + path);
-    }
+    private:
+      boost::weak_ptr<IObserver> receiver_;
+      IMessageEmitter&           emitter_;
+      boost::shared_ptr<ParsedDicomFileCache>  cache_;
+
+    public:
+      DicomHandlerWithCache(boost::weak_ptr<IObserver> receiver,
+                            IMessageEmitter& emitter,
+                            boost::shared_ptr<ParsedDicomFileCache> cache) :
+        receiver_(receiver),
+        emitter_(emitter),
+        cache_(cache)
+      {
+        if (!cache)
+        {
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+        }
+      }
+      
+      virtual void Handle(Orthanc::ParsedDicomFile* dicom,
+                          const ParseDicomFileCommand& command,
+                          uint64_t fileSize)
+      {
+        std::auto_ptr<Orthanc::ParsedDicomFile> parsed(dicom);
+
+        {
+          ParseDicomFileCommand::SuccessMessage message
+            (command, *parsed, static_cast<size_t>(fileSize), command.IsPixelDataIncluded());
+          emitter_.EmitMessage(receiver_, message);
+        }
+
+        // Store it into the cache for future use
+        assert(cache_);
+        cache_->Acquire(command.GetPath(), parsed.release(),
+                        static_cast<size_t>(fileSize), command.IsPixelDataIncluded());
+      }
+    };
   }
 
   
@@ -305,8 +384,7 @@
                           const std::string& root,
                           const ParseDicomFileCommand& command)
   {
-#if 0
-    // The code to use the cache is buggy in multithreaded environments => TODO FIX
+#if 1
     if (cache.get())
     {
       {
@@ -316,30 +394,25 @@
              reader.HasPixelData()))
         {
           // Reuse the DICOM file from the cache
-          return new ParseDicomFileCommand::SuccessMessage(
+          ParseDicomFileCommand::SuccessMessage message(
             command, reader.GetDicom(), reader.GetFileSize(), reader.HasPixelData());
           emitter.EmitMessage(receiver, message);
           return;
         }
       }
       
-      // Not in the cache, first read and parse the DICOM file
-      std::auto_ptr<ParseDicomFileCommand::SuccessMessage> message(RunInternal(root, command));
-
-      // Secondly, store it into the cache for future use
-      assert(&message->GetOrigin() == &command);
-      cache->Acquire(message->GetOrigin().GetPath(), message->GetDicom(),
-                     message->GetFileSize(), message->HasPixelData());
-
-      return message.release();
+      DicomHandlerWithCache handler(receiver, emitter, cache);
+      IDicomHandler::Apply(handler, root, command);
     }
     else
     {
       // No cache available
-      return RunInternal(root, command);
+      DicomHandlerWithoutCache handler(receiver, emitter);
+      IDicomHandler::Apply(handler, root, command);
     }
 #else
-    return RunInternal(receiver, emitter, root, command);
+    DicomHandlerWithoutCache handler(receiver, emitter);
+    IDicomHandler::Apply(handler, root, command);
 #endif
   }
   
--- a/Framework/Toolbox/ParsedDicomFileCache.cpp	Wed Nov 06 17:34:58 2019 +0100
+++ b/Framework/Toolbox/ParsedDicomFileCache.cpp	Wed Nov 06 17:54:14 2019 +0100
@@ -26,13 +26,13 @@
   class ParsedDicomFileCache::Item : public Orthanc::ICacheable
   {
   private:
-    boost::mutex                                 mutex_;
-    boost::shared_ptr<Orthanc::ParsedDicomFile>  dicom_;
-    size_t                                       fileSize_;
-    bool                                         hasPixelData_;
+    boost::mutex                             mutex_;
+    std::auto_ptr<Orthanc::ParsedDicomFile>  dicom_;
+    size_t                                   fileSize_;
+    bool                                     hasPixelData_;
     
   public:
-    Item(boost::shared_ptr<Orthanc::ParsedDicomFile> dicom,
+    Item(Orthanc::ParsedDicomFile* dicom,
          size_t fileSize,
          bool hasPixelData) :
       dicom_(dicom),
@@ -55,10 +55,10 @@
       return fileSize_;
     }
 
-    boost::shared_ptr<Orthanc::ParsedDicomFile> GetDicom() const
+    Orthanc::ParsedDicomFile& GetDicom() const
     {
       assert(dicom_.get() != NULL);
-      return dicom_;
+      return *dicom_;
     }
 
     bool HasPixelData() const
@@ -69,7 +69,7 @@
     
 
   void ParsedDicomFileCache::Acquire(const std::string& path,
-                                     boost::shared_ptr<Orthanc::ParsedDicomFile> dicom,
+                                     Orthanc::ParsedDicomFile* dicom,
                                      size_t fileSize,
                                      bool hasPixelData)
   {
@@ -114,7 +114,7 @@
   }
 
   
-  boost::shared_ptr<Orthanc::ParsedDicomFile> ParsedDicomFileCache::Reader::GetDicom() const
+  Orthanc::ParsedDicomFile& ParsedDicomFileCache::Reader::GetDicom() const
   {
     if (item_ == NULL)
     {
--- a/Framework/Toolbox/ParsedDicomFileCache.h	Wed Nov 06 17:34:58 2019 +0100
+++ b/Framework/Toolbox/ParsedDicomFileCache.h	Wed Nov 06 17:54:14 2019 +0100
@@ -24,8 +24,6 @@
 #include <Core/Cache/MemoryObjectCache.h>
 #include <Core/DicomParsing/ParsedDicomFile.h>
 
-#include <boost/shared_ptr.hpp>
-
 namespace OrthancStone
 {
   class ParsedDicomFileCache : public boost::noncopyable
@@ -42,7 +40,7 @@
     }
     
     void Acquire(const std::string& path,
-                 boost::shared_ptr<Orthanc::ParsedDicomFile> dicom,
+                 Orthanc::ParsedDicomFile* dicom,
                  size_t fileSize,
                  bool hasPixelData);
 
@@ -64,7 +62,7 @@
 
       bool HasPixelData() const;
 
-      boost::shared_ptr<Orthanc::ParsedDicomFile> GetDicom() const;
+      Orthanc::ParsedDicomFile& GetDicom() const;
 
       size_t GetFileSize() const;
     };