changeset 1944:3daecfa5791c

rendering plugin: caching multiple rt-struct in memory
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 02 Jun 2022 11:45:28 +0200
parents a601b8abc1cb
children 98952be6fb97
files RenderingPlugin/Sources/Plugin.cpp
diffstat 1 files changed, 61 insertions(+), 45 deletions(-) [+]
line wrap: on
line diff
--- a/RenderingPlugin/Sources/Plugin.cpp	Thu Jun 02 10:52:47 2022 +0200
+++ b/RenderingPlugin/Sources/Plugin.cpp	Thu Jun 02 11:45:28 2022 +0200
@@ -27,11 +27,9 @@
 #include "../../OrthancStone/Sources/Toolbox/DicomInstanceParameters.h"
 #include "../../OrthancStone/Sources/Toolbox/DicomStructureSet.h"
 
-#include <EmbeddedResources.h>
-
+#include <Cache/MemoryObjectCache.h>
 #include <Images/Image.h>
 #include <Images/ImageProcessing.h>
-#include <Images/PngWriter.h>
 #include <Images/NumpyWriter.h>
 #include <Logging.h>
 #include <SerializationToolbox.h>
@@ -49,9 +47,33 @@
 class DicomStructureCache : public boost::noncopyable
 {
 private:
-  boost::mutex   mutex_;
-  std::string    instanceId_;
-  std::unique_ptr<OrthancStone::DicomStructureSet> rtstruct_;
+  class Item : public Orthanc::ICacheable
+  {
+  private:
+    std::unique_ptr<OrthancStone::DicomStructureSet> rtstruct_;
+
+  public:
+    Item(OrthancStone::DicomStructureSet* rtstruct) :
+      rtstruct_(rtstruct)
+    {
+      if (rtstruct == NULL)
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+      }
+    }
+    
+    virtual size_t GetMemoryUsage() const
+    {
+      return 1;
+    }
+
+    OrthancStone::DicomStructureSet& GetRtStruct() const
+    {
+      return *rtstruct_;
+    }
+  };
+
+  Orthanc::MemoryObjectCache   cache_;
 
   DicomStructureCache()  // Singleton design pattern
   {
@@ -60,12 +82,12 @@
 public:
   void Invalidate(const std::string& instanceId)
   {
-    boost::mutex::scoped_lock lock(mutex_);
+    cache_.Invalidate(instanceId);
+  }
 
-    if (instanceId_ == instanceId)
-    {
-      rtstruct_.reset(NULL);
-    }
+  void SetMaximumNumberOfItems(size_t items)
+  {
+    cache_.SetMaximumSize(items);
   }
 
   static DicomStructureCache& GetSingleton()
@@ -77,34 +99,39 @@
   class Accessor : public boost::noncopyable
   {
   private:
-    boost::mutex::scoped_lock         lock_;
-    std::string                       instanceId_;
-    OrthancStone::DicomStructureSet*  rtstruct_;
+    DicomStructureCache& that_;
+    std::string instanceId_;
+    Orthanc::MemoryObjectCache::Accessor  lock_;
+    std::unique_ptr<OrthancStone::DicomStructureSet>  notCached_;
 
   public:
     Accessor(DicomStructureCache& that,
              const std::string& instanceId) :
-      lock_(that.mutex_),
+      that_(that),
       instanceId_(instanceId),
-      rtstruct_(NULL)
+      lock_(that.cache_, instanceId, true /* unique, as "GetRtStruct()" is mutable */)
     {
-      if (that.instanceId_ == instanceId &&
-          that.rtstruct_.get() != NULL)
+      if (!lock_.IsValid())
       {
-        rtstruct_ = that.rtstruct_.get();
+        OrthancStone::OrthancPluginConnection connection;
+        OrthancStone::FullOrthancDataset dataset(connection, "/instances/" + instanceId + "/tags?ignore-length=3006-0050");
+        notCached_.reset(new OrthancStone::DicomStructureSet(dataset));
       }
-      else
+    }
+
+    ~Accessor()
+    {
+      if (!lock_.IsValid())
       {
+        assert(notCached_.get() != NULL);
+      
         try
         {
-          OrthancStone::OrthancPluginConnection connection;
-          OrthancStone::FullOrthancDataset dataset(connection, "/instances/" + instanceId + "/tags?ignore-length=3006-0050");
-          that.rtstruct_.reset(new OrthancStone::DicomStructureSet(dataset));
-          that.instanceId_ = instanceId;
-          rtstruct_ = that.rtstruct_.get();
+          that_.cache_.Acquire(instanceId_, new Item(notCached_.release()));
         }
-        catch (Orthanc::OrthancException&)
+        catch (Orthanc::OrthancException& e)
         {
+          LOG(ERROR) << "Cannot insert RT-STRUCT into cache: " << e.What();
         }
       }
     }
@@ -114,20 +141,16 @@
       return instanceId_;
     }
 
-    bool IsValid() const
-    {
-      return rtstruct_ != NULL;
-    }
-
     OrthancStone::DicomStructureSet& GetRtStruct() const
     {
-      if (IsValid())
+      if (lock_.IsValid())
       {
-        return *rtstruct_;
+        return dynamic_cast<Item&>(lock_.GetValue()).GetRtStruct();
       }
       else
       {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+        assert(notCached_.get() != NULL);
+        return *notCached_;
       }
     }
   };
@@ -298,6 +321,7 @@
     targetWidth_ = 0;
     targetHeight_ = 0;
     hasInterpolation_ = false;
+    interpolation_ = OrthancStone::ImageInterpolation_Nearest;
   }
 
   
@@ -635,11 +659,6 @@
 {
   DicomStructureCache::Accessor accessor(DicomStructureCache::GetSingleton(), request->groups[0]);
 
-  if (!accessor.IsValid())
-  {
-    throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentItem);
-  }
-
   Json::Value answer;
   answer[STRUCTURES] = Json::arrayValue;
 
@@ -671,7 +690,7 @@
     s.ToString(t);
 
     answer[INSTANCES].append(t);
-  }  
+  }
 
   std::string s = answer.toStyledString();
   OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, s.c_str(), s.size(), "application/json");
@@ -773,11 +792,6 @@
   {
     DicomStructureCache::Accessor accessor(DicomStructureCache::GetSingleton(), request->groups[0]);
 
-    if (!accessor.IsValid())
-    {
-      throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentItem);
-    }
-
     size_t structureIndex;
     bool found = false;
     for (size_t i = 0; i < accessor.GetRtStruct().GetStructuresCount(); i++)
@@ -889,6 +903,8 @@
 
     try
     {
+      DicomStructureCache::GetSingleton().SetMaximumNumberOfItems(1024);  // Cache up to 1024 RT-STRUCT instances
+      
       OrthancPlugins::RegisterRestCallback<RenderNumpyFrame>("/stone/instances/([^/]+)/frames/([0-9]+)/numpy", true);
       OrthancPlugins::RegisterRestCallback<ListRtStruct>("/stone/rt-struct", true);
       OrthancPlugins::RegisterRestCallback<GetRtStruct>("/stone/rt-struct/([^/]+)/info", true);