diff OrthancFramework/Sources/DicomParsing/ParsedDicomCache.cpp @ 4456:3e4f7b7840f0

new class: ParsedDicomCache()
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 19 Jan 2021 16:11:23 +0100
parents
children 789676a8c96a
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancFramework/Sources/DicomParsing/ParsedDicomCache.cpp	Tue Jan 19 16:11:23 2021 +0100
@@ -0,0 +1,186 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2021 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "../PrecompiledHeaders.h"
+#include "ParsedDicomCache.h"
+
+#include "../OrthancException.h"
+
+namespace Orthanc
+{
+  class ParsedDicomCache::Item : public ICacheable
+  {
+  private:
+    std::unique_ptr<ParsedDicomFile>  dicom_;
+    size_t                            fileSize_;
+
+  public:
+    Item(ParsedDicomFile* dicom,
+         size_t fileSize) :
+      dicom_(dicom),
+      fileSize_(fileSize)
+    {
+      if (dicom == NULL)
+      {
+        throw OrthancException(ErrorCode_NullPointer);
+      }
+    }
+
+    virtual size_t GetMemoryUsage() const ORTHANC_OVERRIDE
+    {
+      return fileSize_;
+    }
+
+    ParsedDicomFile& GetDicom() const
+    {
+      assert(dicom_.get() != NULL);
+      return *dicom_;
+    }
+  };
+
+
+  ParsedDicomCache::ParsedDicomCache(size_t size) :
+    cacheSize_(size),
+    largeSize_(0)
+  {
+    if (size == 0)
+    {
+      throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+  }
+
+  
+  size_t ParsedDicomCache::GetCurrentSize()  // For unit tests only
+  {
+    boost::mutex::scoped_lock lock(mutex_);
+
+    if (cache_.get() == NULL)
+    {
+      return largeSize_;
+    }
+    else
+    {
+      assert(largeSize_ == 0);
+      return cache_->GetCurrentSize();
+    }
+  }
+
+  
+  void ParsedDicomCache::Invalidate(const std::string& id)
+  {
+    boost::mutex::scoped_lock lock(mutex_);
+      
+    if (cache_.get() != NULL)
+    {
+      cache_->Invalidate(id);
+    }
+
+    if (largeId_ == id)
+    {
+      largeDicom_.reset(NULL);
+      largeSize_ = 0;
+    }
+  }
+
+  
+  void ParsedDicomCache::Acquire(const std::string& id,
+                                 ParsedDicomFile* dicom,  // Takes ownership
+                                 size_t fileSize)
+  {
+    boost::mutex::scoped_lock lock(mutex_);
+      
+    if (fileSize >= cacheSize_)
+    {
+      cache_.reset(NULL);
+      largeDicom_.reset(dicom);
+      largeId_ = id;
+      largeSize_ = fileSize;
+    }
+    else
+    {
+      largeDicom_.reset(NULL);
+      largeSize_ = 0;
+
+      if (cache_.get() == NULL)
+      {
+        cache_.reset(new MemoryObjectCache);
+        cache_->SetMaximumSize(cacheSize_);
+      }
+
+      cache_->Acquire(id, new Item(dicom, fileSize));
+    }
+  }
+
+
+  ParsedDicomCache::Accessor::Accessor(ParsedDicomCache& that,
+                                       const std::string& id) :
+    lock_(that.mutex_),
+    id_(id),
+    file_(NULL),
+    fileSize_(0)
+  {
+    if (that.largeDicom_.get() != NULL &&
+        that.largeId_ == id)
+    {
+      file_ = that.largeDicom_.get();
+      fileSize_ = that.largeSize_;
+    }
+    else if (that.cache_.get() != NULL)
+    {
+      accessor_.reset(new MemoryObjectCache::Accessor(
+                        *that.cache_, id, true /* unique */));
+      if (accessor_->IsValid())
+      {            
+        const Item& item = dynamic_cast<const Item&>(accessor_->GetValue());
+        file_ = &item.GetDicom();
+        fileSize_ = item.GetMemoryUsage();
+      }
+    }
+  }
+
+
+  ParsedDicomFile& ParsedDicomCache::Accessor::GetDicom() const
+  {
+    if (IsValid())
+    {
+      assert(file_ != NULL);
+      return *file_;
+    }
+    else
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+  }
+
+
+  size_t ParsedDicomCache::Accessor::GetFileSize() const
+  {
+    if (IsValid())
+    {
+      return fileSize_;
+    }
+    else
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+  }
+}