Mercurial > hg > orthanc
changeset 6797:4b1c0418a4ef
Release large-DICOM semaphore lock early (for better performance)
| author | Alain Mazy <am@orthanc.team> |
|---|---|
| date | Mon, 18 May 2026 13:12:55 +0200 |
| parents | 7872e2d293bb |
| children | 8ac77592226e |
| files | OrthancServer/Sources/ServerContext.cpp OrthancServer/Sources/ServerContext.h |
| diffstat | 2 files changed, 40 insertions(+), 8 deletions(-) [+] |
line wrap: on
line diff
--- a/OrthancServer/Sources/ServerContext.cpp Mon May 18 09:15:19 2026 +0200 +++ b/OrthancServer/Sources/ServerContext.cpp Mon May 18 13:12:55 2026 +0200 @@ -1404,6 +1404,16 @@ std::string& attachmentId, const std::string& instancePublicId) { + std::unique_ptr<Semaphore::Locker> dummyLargeDicomLocker; // only the DicomCacheLocker uses a real largeDicomLocker_ + ReadDicomInternal(dicom, attachmentId, instancePublicId, dummyLargeDicomLocker, 0); + } + + void ServerContext::ReadDicomInternal(std::string& dicom, + std::string& attachmentId, + const std::string& instancePublicId, + std::unique_ptr<Semaphore::Locker>& largeDicomLocker, + std::size_t largeDicomThreshold) + { FileInfo attachment; int64_t revision; @@ -1417,6 +1427,11 @@ assert(attachment.GetContentType() == FileContentType_Dicom); attachmentId = attachment.GetUuid(); + if (attachment.GetUncompressedSize() < largeDicomThreshold) // release ASAP (before the read) if we don't plan to hold the lock (https://discourse.orthanc-server.org/t/patch-release-large-dicom-semaphore-lock-early-for-better-performance/6440) + { + largeDicomLocker.reset(NULL); + } + ReadAttachment(dicom, attachment, true /* uncompress */); } @@ -1428,6 +1443,15 @@ ReadDicom(dicom, attachmentId, instancePublicId); } + void ServerContext::ReadDicomInternal(std::string& dicom, + const std::string& instancePublicId, + std::unique_ptr<Semaphore::Locker>& largeDicomLocker, + std::size_t largeDicomThreshold) + { + std::string attachmentId; + ReadDicomInternal(dicom, attachmentId, instancePublicId, largeDicomLocker, largeDicomThreshold); + } + void ServerContext::ReadDicomForHeader(std::string& dicom, const std::string& instancePublicId) { @@ -1540,17 +1564,12 @@ { accessor_.reset(NULL); - // Throttle to avoid loading several large DICOM files simultaneously + // Throttle to avoid loading several large DICOM files simultaneously (since the ParsedDicomCache is 128MB, loading multiple 50MB files would throw them out directly after loading) largeDicomLocker_.reset(new Semaphore::Locker(context.largeDicomThrottler_)); - context_.ReadDicom(buffer_, instancePublicId_); - // Release the throttle if loading "small" DICOM files (under // 50MB, which is an arbitrary value) - if (buffer_.size() < static_cast<size_t>(50) * 1024 * 1024) - { - largeDicomLocker_.reset(NULL); - } + context_.ReadDicomInternal(buffer_, instancePublicId_, largeDicomLocker_, static_cast<size_t>(50) * 1024 * 1024); dicom_.reset(new ParsedDicomFile(buffer_)); dicomSize_ = buffer_.size();
--- a/OrthancServer/Sources/ServerContext.h Mon May 18 09:15:19 2026 +0200 +++ b/OrthancServer/Sources/ServerContext.h Mon May 18 13:12:55 2026 +0200 @@ -398,9 +398,22 @@ void ReadDicomAsJson(Json::Value& result, const std::string& instancePublicId); // TODO-FIND: Can this be removed? +private: + void ReadDicomInternal(std::string& dicom, + const std::string& instancePublicId, + std::unique_ptr<Semaphore::Locker>& largeDicomLocker, + std::size_t largeDicomThreshold); + + void ReadDicomInternal(std::string& dicom, + std::string& attachmentId, + const std::string& instancePublicId, + std::unique_ptr<Semaphore::Locker>& largeDicomLocker, + std::size_t largeDicomThreshold); + +public: void ReadDicom(std::string& dicom, const std::string& instancePublicId); - + void ReadDicom(std::string& dicom, std::string& attachmentId, const std::string& instancePublicId);
