# HG changeset patch # User Sebastien Jodogne # Date 1790673629 -7200 # Node ID e499cac2a0486eb87fa640ec2fae0f86616cfb51 # Parent 4c1342615306816bef1f437f4d5b7267fb752b23 created a new version of the DICOM cache diff -r 4c1342615306 -r e499cac2a048 Applications/Samples/Sdl/SingleFrameViewer/SdlSimpleViewer.cpp --- a/Applications/Samples/Sdl/SingleFrameViewer/SdlSimpleViewer.cpp Tue Sep 29 10:10:40 2026 +0200 +++ b/Applications/Samples/Sdl/SingleFrameViewer/SdlSimpleViewer.cpp Tue Sep 29 11:20:29 2026 +0200 @@ -56,6 +56,7 @@ // TODO Refactoring +#include "../../../../OrthancStone/Sources/Oracle/ParseDicomFromFileCommand.h" #include "../../../../OrthancStone/Sources/Oracle/SleepOracleCommand.h" #include "../../../../OrthancStone/Sources/StoneApplication.h" @@ -221,6 +222,7 @@ OrthancStone::StoneApplication::Configuration configuration; configuration.SetRemoteOrthancParameters(orthancWebService); + configuration.SetRootDirectory("/tmp"); // TODO Refactoring - Remove this OrthancStone::StoneApplication::Initialize(configuration); @@ -325,6 +327,13 @@ command->SetUri("/system/"); oracle.Submit(environment, toto_, command.release()); } + + for (unsigned int i = 0; i < 10; i++) + { + DicomSource source; + source.SetDicomDirSource(); + oracle.Submit(environment, toto_, new OrthancStone::ParseDicomFromFileCommand(source, "hand.dcm")); + } break; } diff -r 4c1342615306 -r e499cac2a048 OrthancStone/Sources/Platforms/Native/GenericOracleRunner.cpp --- a/OrthancStone/Sources/Platforms/Native/GenericOracleRunner.cpp Tue Sep 29 10:10:40 2026 +0200 +++ b/OrthancStone/Sources/Platforms/Native/GenericOracleRunner.cpp Tue Sep 29 11:20:29 2026 +0200 @@ -40,8 +40,6 @@ # include "../../Oracle/ParseDicomSuccessMessage.h" # include # include -static unsigned int BUCKET_DICOMDIR = 0; -static unsigned int BUCKET_SOP = 1; #endif #include @@ -54,6 +52,17 @@ #include +static std::string GetFileSystemCacheKey(const std::string& path) +{ + return "file|" + path; +} + + +static std::string GetSopInstanceUidCacheKey(const std::string& uid) +{ + return "sop|" + uid; +} + namespace OrthancStone { @@ -333,32 +342,32 @@ "Cannot parse file: " + path); } } +#endif +#if ORTHANC_ENABLE_DCMTK == 1 static void RunInternal(IOracleCallback& callback, - boost::shared_ptr cache, + boost::shared_ptr cache, const std::string& root, const ParseDicomFromFileCommand& command) { const std::string path = GetPath(root, command.GetPath()); - -#if 0 - // TODO Refactoring - Reactivate the cache!!! + const std::string cacheKey = GetFileSystemCacheKey(path); if (cache) { - ParsedDicomCache::Reader reader(*cache, BUCKET_DICOMDIR, path); - if (reader.IsValid() && - (!command.IsPixelDataIncluded() || - reader.HasPixelData())) + New::ParsedDicomCache::Accessor accessor(*cache, cacheKey); + + if (accessor.IsValid()) { + assert(accessor.HasPixelData()); + // Reuse the DICOM file from the cache - callback.NotifySuccess(new ParseDicomSuccessMessage(command, command.GetSource(), reader.GetDicom(), - reader.GetFileSize(), reader.HasPixelData())); + callback.NotifySuccess(new ParseDicomSuccessMessage(command, command.GetSource(), accessor.GetDicom(), + accessor.GetFileSize(), accessor.HasPixelData())); return; } } -#endif uint64_t fileSize; boost::shared_ptr parsed(ParseDicom(fileSize, path, command.IsPixelDataIncluded())); @@ -372,43 +381,37 @@ callback.NotifySuccess(new ParseDicomSuccessMessage(command, command.GetSource(), parsed, static_cast(fileSize), command.IsPixelDataIncluded())); -#if 0 - // TODO Refactoring - Reactivate the cache!!! - if (cache) + if (cache && + command.IsPixelDataIncluded()) { - // Store it into the cache for future use - - // Invalidate to overwrite DICOM instance that would already - // be stored without pixel data - cache->Invalidate(BUCKET_DICOMDIR, path); - - cache->Acquire(BUCKET_DICOMDIR, path, parsed.release(), - static_cast(fileSize), command.IsPixelDataIncluded()); + cache->Store(cacheKey, parsed, static_cast(fileSize), command.IsPixelDataIncluded()); } + } #endif - } + - +#if ORTHANC_ENABLE_DCMTK == 1 static void RunInternal(IOracleCallback& callback, - boost::shared_ptr cache, + boost::shared_ptr cache, const Orthanc::WebServiceParameters& orthanc, const ParseDicomFromWadoCommand& command) { -#if 0 - // TODO Refactoring - Reactivate the cache!!! + const std::string cacheKey = GetSopInstanceUidCacheKey(command.GetSopInstanceUid()); + if (cache) { - ParsedDicomCache::Reader reader(*cache, BUCKET_SOP, command.GetSopInstanceUid()); - if (reader.IsValid() && - reader.HasPixelData()) + New::ParsedDicomCache::Accessor accessor(*cache, cacheKey); + + if (accessor.IsValid()) { + assert(accessor.HasPixelData()); + // Reuse the DICOM file from the cache - callback.NotifySuccess(new ParseDicomSuccessMessage(command, command.GetSource(), reader.GetDicom(), - reader.GetFileSize(), reader.HasPixelData())); + callback.NotifySuccess(new ParseDicomSuccessMessage(command, command.GetSource(), accessor.GetDicom(), + accessor.GetFileSize(), accessor.HasPixelData())); return; } } -#endif std::string answer; Orthanc::HttpClient::HttpHeaders answerHeaders; @@ -434,14 +437,11 @@ callback.NotifySuccess(new ParseDicomSuccessMessage(command, command.GetSource(), parsed, fileSize, true /* pixel data always is included in WADO-RS */)); -#if 0 - // TODO Refactoring - Reactivate the cache!!! if (cache) { // Store it into the cache for future use - cache->Acquire(BUCKET_SOP, command.GetSopInstanceUid(), parsed.release(), fileSize, true); + cache->Store(cacheKey, parsed, static_cast(fileSize), true); } -#endif } #endif diff -r 4c1342615306 -r e499cac2a048 OrthancStone/Sources/Platforms/Native/GenericOracleRunner.h --- a/OrthancStone/Sources/Platforms/Native/GenericOracleRunner.h Tue Sep 29 10:10:40 2026 +0200 +++ b/OrthancStone/Sources/Platforms/Native/GenericOracleRunner.h Tue Sep 29 11:20:29 2026 +0200 @@ -48,7 +48,7 @@ StoneApplication::Configuration configuration_; #if ORTHANC_ENABLE_DCMTK == 1 - boost::shared_ptr dicomCache_; + boost::shared_ptr dicomCache_; #endif public: @@ -58,7 +58,7 @@ } #if ORTHANC_ENABLE_DCMTK == 1 - void SetDicomCache(boost::shared_ptr cache) + void SetDicomCache(boost::shared_ptr cache) { dicomCache_ = cache; } diff -r 4c1342615306 -r e499cac2a048 OrthancStone/Sources/Platforms/Native/ThreadedOracle.cpp --- a/OrthancStone/Sources/Platforms/Native/ThreadedOracle.cpp Tue Sep 29 10:10:40 2026 +0200 +++ b/OrthancStone/Sources/Platforms/Native/ThreadedOracle.cpp Tue Sep 29 11:20:29 2026 +0200 @@ -165,8 +165,9 @@ } else { - LOG(INFO) << "The DICOM cache size is set to " << configuration.GetDicomCacheSize() << " bytes"; - dicomCache_.reset(new ParsedDicomCache(configuration.GetDicomCacheSize())); + LOG(INFO) << "The DICOM cache size is set to " + << (static_cast(configuration.GetDicomCacheSize()) / static_cast(1024 * 1024)) << " MB"; + dicomCache_.reset(new New::ParsedDicomCache(configuration.GetDicomCacheSize())); } } diff -r 4c1342615306 -r e499cac2a048 OrthancStone/Sources/Platforms/Native/ThreadedOracle.h --- a/OrthancStone/Sources/Platforms/Native/ThreadedOracle.h Tue Sep 29 10:10:40 2026 +0200 +++ b/OrthancStone/Sources/Platforms/Native/ThreadedOracle.h Tue Sep 29 11:20:29 2026 +0200 @@ -64,7 +64,7 @@ Orthanc::ThreadPool threadPool_; #if ORTHANC_ENABLE_DCMTK == 1 - boost::shared_ptr dicomCache_; + boost::shared_ptr dicomCache_; #endif void SubmitInternal(IOracleCallback* callback /* takes ownership */); diff -r 4c1342615306 -r e499cac2a048 OrthancStone/Sources/Platforms/WebAssembly/WebAssemblyOracle.cpp --- a/OrthancStone/Sources/Platforms/WebAssembly/WebAssemblyOracle.cpp Tue Sep 29 10:10:40 2026 +0200 +++ b/OrthancStone/Sources/Platforms/WebAssembly/WebAssemblyOracle.cpp Tue Sep 29 11:20:29 2026 +0200 @@ -797,7 +797,8 @@ } else { - LOG(INFO) << "The DICOM cache size is set to " << configuration.GetDicomCacheSize() << " bytes"; + LOG(INFO) << "The DICOM cache size is set to " + << (static_cast(configuration.GetDicomCacheSize()) / static_cast(1024 * 1024)) << " MB"; dicomCache_.reset(new ParsedDicomCache(configuration.GetDicomCacheSize())); } #else diff -r 4c1342615306 -r e499cac2a048 OrthancStone/Sources/StoneApplication.cpp --- a/OrthancStone/Sources/StoneApplication.cpp Tue Sep 29 10:10:40 2026 +0200 +++ b/OrthancStone/Sources/StoneApplication.cpp Tue Sep 29 11:20:29 2026 +0200 @@ -45,7 +45,7 @@ rootDirectory_("."), oracleThreadsCount_(4), workersTimeResolution_(50), // By default, time resolution of 50ms - dicomCacheSize_(0) // By default, no DICOM cache + dicomCacheSize_(128 * 1024 * 1024) // By default, use a cache of 128MB { } diff -r 4c1342615306 -r e499cac2a048 OrthancStone/Sources/Toolbox/ParsedDicomCache.cpp --- a/OrthancStone/Sources/Toolbox/ParsedDicomCache.cpp Tue Sep 29 10:10:40 2026 +0200 +++ b/OrthancStone/Sources/Toolbox/ParsedDicomCache.cpp Tue Sep 29 11:20:29 2026 +0200 @@ -158,4 +158,67 @@ return item_->GetMemoryUsage(); } } + + + namespace New + { + ParsedDicomCache::Item::Item(const boost::shared_ptr& dicom, + size_t fileSize, + bool hasPixelData) : + dicom_(dicom), + fileSize_(fileSize), + hasPixelData_(hasPixelData) + { + if (dicom == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + } + + + void ParsedDicomCache::Store(const std::string& key, + const boost::shared_ptr& dicom, + size_t fileSize, + bool hasPixelData) + { + if (dicom == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + else + { + cache_.Store(key, boost::shared_ptr(new Item(dicom, fileSize, hasPixelData)), fileSize); + } + } + + + ParsedDicomCache::Accessor::Accessor(ParsedDicomCache& cache, + const std::string& key) : + item_(cache.cache_.GetCachedValue(key)) + { + if (item_) + { + lock_.reset(new Orthanc::Mutex::ScopedLock(dynamic_cast(*item_).GetMutex())); + } + } + + + bool ParsedDicomCache::Accessor::IsValid() const + { + return (item_ ? true : false); + } + + + const ParsedDicomCache::Item& ParsedDicomCache::Accessor::GetItem() const + { + if (item_) + { + return dynamic_cast(*item_); + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + } + } } diff -r 4c1342615306 -r e499cac2a048 OrthancStone/Sources/Toolbox/ParsedDicomCache.h --- a/OrthancStone/Sources/Toolbox/ParsedDicomCache.h Tue Sep 29 10:10:40 2026 +0200 +++ b/OrthancStone/Sources/Toolbox/ParsedDicomCache.h Tue Sep 29 11:20:29 2026 +0200 @@ -23,12 +23,13 @@ #pragma once -#include +#include +#include // TODO Refactoring - Remove this #include namespace OrthancStone { - class ParsedDicomCache : public boost::noncopyable + class ParsedDicomCache : public boost::noncopyable // TODO Refactoring - Remove this { private: class Item; @@ -81,4 +82,94 @@ size_t GetFileSize() const; }; }; + + + namespace New + { + class ParsedDicomCache : public boost::noncopyable + { + private: + class Item : public Orthanc::IDynamicObject + { + private: + Orthanc::Mutex mutex_; + boost::shared_ptr dicom_; + size_t fileSize_; + bool hasPixelData_; + + public: + Item(const boost::shared_ptr& dicom, + size_t fileSize, + bool hasPixelData); + + Orthanc::Mutex& GetMutex() + { + return mutex_; + } + + const boost::shared_ptr& GetDicom() const + { + return dicom_; + } + + size_t GetFileSize() const + { + return fileSize_; + } + + bool HasPixelData() const + { + return hasPixelData_; + } + }; + + Orthanc::SharedObjectCache cache_; + + public: + ParsedDicomCache(uint64_t capacity) : + cache_(capacity) + { + } + + void Store(const std::string& key, + const boost::shared_ptr& dicom, + size_t fileSize, + bool hasPixelData); + + void Invalidate(const std::string& key) + { + cache_.Invalidate(key); + } + + class Accessor : public boost::noncopyable + { + private: + boost::shared_ptr item_; + std::unique_ptr lock_; + + const Item& GetItem() const; + + public: + Accessor(ParsedDicomCache& cache, + const std::string& key); + + bool IsValid() const; + + const boost::shared_ptr& GetDicom() const + { + return GetItem().GetDicom(); + } + + size_t GetFileSize() const + { + return GetItem().GetFileSize(); + } + + bool HasPixelData() const + { + return GetItem().HasPixelData(); + } + }; + }; + } }