changeset 5427:111e21b4f8bc

fix transcoded instance caching
author Alain Mazy <am@osimis.io>
date Fri, 17 Nov 2023 08:22:17 +0100
parents c65e036d649b
children 8174e45f48d8
files OrthancFramework/Sources/Cache/MemoryStringCache.cpp OrthancFramework/Sources/Cache/MemoryStringCache.h OrthancFramework/Sources/FileStorage/StorageCache.cpp OrthancFramework/Sources/FileStorage/StorageCache.h OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp OrthancServer/Sources/ServerContext.cpp OrthancServer/Sources/ServerContext.h
diffstat 7 files changed, 68 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancFramework/Sources/Cache/MemoryStringCache.cpp	Thu Nov 16 16:09:04 2023 +0100
+++ b/OrthancFramework/Sources/Cache/MemoryStringCache.cpp	Fri Nov 17 08:22:17 2023 +0100
@@ -206,24 +206,6 @@
   }
 
 
-  void MemoryStringCache::InvalidateByPrefix(const std::string& keyPrefix)
-  {
-    std::vector<std::string> allKeys;
-
-    {
-      boost::mutex::scoped_lock cacheLock(cacheMutex_);
-      content_.GetAllKeys(allKeys);
-    }
-
-    for (std::vector<std::string>::const_iterator it = allKeys.begin(); it != allKeys.end(); ++it)
-    {
-      if (it->find(keyPrefix) == 0)
-      {
-        Invalidate(*it);
-      }
-    }
-  }
-
   bool MemoryStringCache::Fetch(std::string& value,
                                 const std::string& key)
   {
--- a/OrthancFramework/Sources/Cache/MemoryStringCache.h	Thu Nov 16 16:09:04 2023 +0100
+++ b/OrthancFramework/Sources/Cache/MemoryStringCache.h	Fri Nov 17 08:22:17 2023 +0100
@@ -50,9 +50,14 @@
   public:
     class Accessor : public boost::noncopyable
     {
+    protected:
       MemoryStringCache& cache_;
+
+    private:
       bool                shouldAdd_;  // when this accessor is the one who should load and add the data
       std::string         keyToAdd_;
+
+
     public:
       Accessor(MemoryStringCache& cache);
       ~Accessor();
@@ -86,8 +91,6 @@
 
     void Invalidate(const std::string& key);
 
-    void InvalidateByPrefix(const std::string& keyPrefix);
-
   private:
     void Add(const std::string& key,
              const std::string& value);
--- a/OrthancFramework/Sources/FileStorage/StorageCache.cpp	Thu Nov 16 16:09:04 2023 +0100
+++ b/OrthancFramework/Sources/FileStorage/StorageCache.cpp	Fri Nov 17 08:22:17 2023 +0100
@@ -50,7 +50,7 @@
   static std::string GetCacheKeyTranscodedInstance(const std::string& uuid,
                                                    DicomTransferSyntax transferSyntax)
   {
-    return uuid + ":" + GetTransferSyntaxUid(transferSyntax) + ":1";
+    return uuid + ":ts:" + GetTransferSyntaxUid(transferSyntax);
   }
 
 
@@ -63,13 +63,31 @@
   void StorageCache::Invalidate(const std::string& uuid,
                                 FileContentType contentType)
   {
+    std::set<DicomTransferSyntax> transferSyntaxes;
+
+    {
+      boost::mutex::scoped_lock lock(subKeysMutex_);
+      transferSyntaxes = subKeysTransferSyntax_;
+    }
+
     // invalidate full file, start range file and possible transcoded instances
-    cache_.InvalidateByPrefix(uuid);
+    const std::string keyFullFile = GetCacheKeyFullFile(uuid, contentType);
+    cache_.Invalidate(keyFullFile);
+
+    const std::string keyPartialFile = GetCacheKeyStartRange(uuid, contentType);
+    cache_.Invalidate(keyPartialFile);
+    
+    for (std::set<DicomTransferSyntax>::const_iterator it = transferSyntaxes.begin(); it != transferSyntaxes.end(); ++it)
+    {
+      const std::string keyTransferSyntax = GetCacheKeyTranscodedInstance(uuid, *it);
+      cache_.Invalidate(keyTransferSyntax);
+    }
   }
 
 
   StorageCache::Accessor::Accessor(StorageCache& cache)
-  : MemoryStringCache::Accessor(cache.cache_)
+  : MemoryStringCache::Accessor(cache.cache_),
+    storageCache_(cache)
   {
   }
 
@@ -138,6 +156,11 @@
                                                      const void* buffer,
                                                      size_t size)
   {
+    {
+      boost::mutex::scoped_lock lock(storageCache_.subKeysMutex_);
+      storageCache_.subKeysTransferSyntax_.insert(targetSyntax);
+    }
+
     const std::string key = GetCacheKeyTranscodedInstance(uuid, targetSyntax);
     MemoryStringCache::Accessor::Add(key, reinterpret_cast<const char*>(buffer), size);
   }
--- a/OrthancFramework/Sources/FileStorage/StorageCache.h	Thu Nov 16 16:09:04 2023 +0100
+++ b/OrthancFramework/Sources/FileStorage/StorageCache.h	Fri Nov 17 08:22:17 2023 +0100
@@ -46,6 +46,7 @@
       // the same file.
       class Accessor : public MemoryStringCache::Accessor
       {
+        StorageCache& storageCache_;
       public:
         Accessor(StorageCache& cache);
 
@@ -82,8 +83,10 @@
       };
 
     private:
-      MemoryStringCache   cache_;
-      
+      MemoryStringCache             cache_;
+      std::set<DicomTransferSyntax> subKeysTransferSyntax_;
+      boost::mutex                  subKeysMutex_;
+
     public:
       void SetMaximumSize(size_t size);
 
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp	Thu Nov 16 16:09:04 2023 +0100
+++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp	Fri Nov 17 08:22:17 2023 +0100
@@ -425,10 +425,11 @@
     if (call.HasArgument(TRANSCODE))
     {
       std::string source;
+      std::string attachmentId;
       std::string transcoded;
-      context.ReadDicom(source, publicId);
-
-      if (context.TranscodeWithCache(transcoded, source, publicId, GetTransferSyntax(call.GetArgument(TRANSCODE, ""))))
+      context.ReadDicom(source, attachmentId, publicId);
+
+      if (context.TranscodeWithCache(transcoded, source, publicId, attachmentId, GetTransferSyntax(call.GetArgument(TRANSCODE, ""))))
       {
         call.GetOutput().AnswerBuffer(transcoded, MimeType_Dicom);
       }
@@ -2328,8 +2329,9 @@
       {
         // Return the raw data (possibly compressed), as stored on the filesystem
         std::string content;
+        std::string attachmentId;
         int64_t revision;
-        context.ReadAttachment(content, revision, publicId, type, false, true /* skipCache when you absolutely need the compressed data */);
+        context.ReadAttachment(content, revision, attachmentId, publicId, type, false, true /* skipCache when you absolutely need the compressed data */);
 
         int64_t userRevision;
         std::string userMD5;
@@ -2511,7 +2513,9 @@
 
     // First check whether the compressed data is correctly stored in the disk
     std::string data;
-    context.ReadAttachment(data, revision, publicId, StringToContentType(name), false, true /* skipCache when you absolutely need the compressed data */);
+    std::string attachmentId;
+
+    context.ReadAttachment(data, revision, attachmentId, publicId, StringToContentType(name), false, true /* skipCache when you absolutely need the compressed data */);
 
     std::string actualMD5;
     Toolbox::ComputeMD5(actualMD5, data);
@@ -2526,7 +2530,7 @@
       }
       else
       {
-        context.ReadAttachment(data, revision, publicId, StringToContentType(name), true, true /* skipCache when you absolutely need the compressed data */);
+        context.ReadAttachment(data, revision, attachmentId, publicId, StringToContentType(name), true, true /* skipCache when you absolutely need the compressed data */);
         Toolbox::ComputeMD5(actualMD5, data);
         ok = (actualMD5 == info.GetUncompressedMD5());
       }
--- a/OrthancServer/Sources/ServerContext.cpp	Thu Nov 16 16:09:04 2023 +0100
+++ b/OrthancServer/Sources/ServerContext.cpp	Fri Nov 17 08:22:17 2023 +0100
@@ -1165,10 +1165,19 @@
 
 
   void ServerContext::ReadDicom(std::string& dicom,
+                                std::string& attachmentId,
                                 const std::string& instancePublicId)
   {
     int64_t revision;
-    ReadAttachment(dicom, revision, instancePublicId, FileContentType_Dicom, true /* uncompress */);
+    ReadAttachment(dicom, revision, attachmentId, instancePublicId, FileContentType_Dicom, true /* uncompress */);
+  }
+
+
+  void ServerContext::ReadDicom(std::string& dicom,
+                                const std::string& instancePublicId)
+  {
+    std::string attachmentId;
+    ReadDicom(dicom, attachmentId, instancePublicId);    
   }
 
   void ServerContext::ReadDicomForHeader(std::string& dicom,
@@ -1236,6 +1245,7 @@
 
   void ServerContext::ReadAttachment(std::string& result,
                                      int64_t& revision,
+                                     std::string& attachmentId,
                                      const std::string& instancePublicId,
                                      FileContentType content,
                                      bool uncompressIfNeeded,
@@ -1250,7 +1260,8 @@
     }
 
     assert(attachment.GetContentType() == content);
-
+    attachmentId = attachment.GetUuid();
+    
     {
       std::unique_ptr<StorageAccessor> accessor;
       
@@ -1951,11 +1962,12 @@
   bool ServerContext::TranscodeWithCache(std::string& target,
                                          const std::string& source,
                                          const std::string& sourceInstanceId,
+                                         const std::string& attachmentId,
                                          DicomTransferSyntax targetSyntax)
   {
     StorageCache::Accessor cacheAccessor(storageCache_);
 
-    if (!cacheAccessor.FetchTranscodedInstance(target, sourceInstanceId, targetSyntax))
+    if (!cacheAccessor.FetchTranscodedInstance(target, attachmentId, targetSyntax))
     {
       IDicomTranscoder::DicomImage sourceDicom;
       sourceDicom.SetExternalBuffer(source);
@@ -1966,7 +1978,7 @@
 
       if (Transcode(targetDicom, sourceDicom, syntaxes, true))
       {
-        cacheAccessor.AddTranscodedInstance(sourceInstanceId, targetSyntax, reinterpret_cast<const char*>(targetDicom.GetBufferData()), targetDicom.GetBufferSize());
+        cacheAccessor.AddTranscodedInstance(attachmentId, targetSyntax, reinterpret_cast<const char*>(targetDicom.GetBufferData()), targetDicom.GetBufferSize());
         target = std::string(reinterpret_cast<const char*>(targetDicom.GetBufferData()), targetDicom.GetBufferSize());
         return true;
       }
--- a/OrthancServer/Sources/ServerContext.h	Thu Nov 16 16:09:04 2023 +0100
+++ b/OrthancServer/Sources/ServerContext.h	Fri Nov 17 08:22:17 2023 +0100
@@ -379,6 +379,10 @@
     void ReadDicom(std::string& dicom,
                    const std::string& instancePublicId);
 
+    void ReadDicom(std::string& dicom,
+                   std::string& attachmentId,
+                   const std::string& instancePublicId);
+
     void ReadDicomForHeader(std::string& dicom,
                             const std::string& instancePublicId);
 
@@ -388,6 +392,7 @@
     // This method is for low-level operations on "/instances/.../attachments/..."
     void ReadAttachment(std::string& result,
                         int64_t& revision,
+                        std::string& attachmentId,
                         const std::string& instancePublicId,
                         FileContentType content,
                         bool uncompressIfNeeded,
@@ -559,6 +564,7 @@
     virtual bool TranscodeWithCache(std::string& target,
                                     const std::string& source,
                                     const std::string& sourceInstanceId,
+                                    const std::string& attachmentId, // for the storage cache
                                     DicomTransferSyntax targetSyntax);
 
     bool IsTranscodeDicomProtocol() const