# HG changeset patch # User Sebastien Jodogne # Date 1589434664 -7200 # Node ID 2910b0d30fe02f5dcf7df200ab77670e8e50230c # Parent dd112d2b83f0aba87552cf67ccc3b62fad0aedbc Allow concurrent calls to the custom image decoders provided by the plugins diff -r dd112d2b83f0 -r 2910b0d30fe0 NEWS --- a/NEWS Wed May 13 18:12:34 2020 +0200 +++ b/NEWS Thu May 14 07:37:44 2020 +0200 @@ -1,10 +1,17 @@ Pending changes in the mainline =============================== +General +------- + +* DICOM transcoding over the REST API +* Transcoding from compressed to uncompressed transfer syntaxes over DICOM + C-STORE SCU (if the remote modality doesn't support compressed syntaxes) + REST API -------- -* API version has been upgraded to 7 +* API version upgraded to 7 * Improved: - "/instances/../modify": it is now possible to "Keep" the "SOPInstanceUID". Note that it was already possible to "Replace" it. @@ -12,8 +19,9 @@ - "/queries/.../answers/../retrieve": "TargetAet" not mandatory anymore (defaults to the local AET) * Changes: - - "/instances/.../modify", ".../archive", ".../media", - "/tools/create-media" and "/tools/create-archive": New option "Transcode" + - "/instances/.../modify": New option "Transcode" + - ".../archive", ".../media", "/tools/create-media" and + "/tools/create-archive": New option "Transcode" - "/ordered-slices": reverted the change introduced in 1.5.8 and go-back to 1.5.7 behaviour. @@ -33,6 +41,7 @@ - OrthancPluginSerializeDicomInstance() - OrthancPluginTranscodeDicomInstance() * "OrthancPluginDicomInstance" structure wrapped in "OrthancPluginCppWrapper.h" +* Allow concurrent calls to the custom image decoders provided by the plugins Maintenance ----------- diff -r dd112d2b83f0 -r 2910b0d30fe0 OrthancServer/OrthancRestApi/OrthancRestResources.cpp --- a/OrthancServer/OrthancRestApi/OrthancRestResources.cpp Wed May 13 18:12:34 2020 +0200 +++ b/OrthancServer/OrthancRestApi/OrthancRestResources.cpp Thu May 14 07:37:44 2020 +0200 @@ -43,6 +43,7 @@ #include "../../Core/Images/Image.h" #include "../../Core/Images/ImageProcessing.h" #include "../../Core/Logging.h" +#include "../../Core/MultiThreading/Semaphore.h" #include "../DefaultDicomImageDecoder.h" #include "../OrthancConfiguration.h" #include "../Search/DatabaseLookup.h" @@ -56,6 +57,14 @@ #include +/** + * This semaphore is used to limit the number of concurrent HTTP + * requests on CPU-intensive routes of the REST API, in order to + * prevent exhaustion of resources (new in Orthanc 1.7.0). + **/ +static Orthanc::Semaphore throttlingSemaphore_(4); // TODO => PARAMETER? + + namespace Orthanc { static void AnswerDicomAsJson(RestApiCall& call, @@ -938,6 +947,8 @@ template static void GetImage(RestApiGetCall& call) { + Semaphore::Locker locker(throttlingSemaphore_); + GetImageHandler handler(mode); IDecodedFrameHandler::Apply(call, handler); } @@ -945,6 +956,8 @@ static void GetRenderedFrame(RestApiGetCall& call) { + Semaphore::Locker locker(throttlingSemaphore_); + RenderedFrameHandler handler; IDecodedFrameHandler::Apply(call, handler); } @@ -952,6 +965,8 @@ static void GetMatlabImage(RestApiGetCall& call) { + Semaphore::Locker locker(throttlingSemaphore_); + ServerContext& context = OrthancRestApi::GetContext(call); std::string frameId = call.GetUriComponent("frame", "0"); diff -r dd112d2b83f0 -r 2910b0d30fe0 Plugins/Engine/OrthancPlugins.cpp --- a/Plugins/Engine/OrthancPlugins.cpp Wed May 13 18:12:34 2020 +0200 +++ b/Plugins/Engine/OrthancPlugins.cpp Thu May 14 07:37:44 2020 +0200 @@ -71,12 +71,13 @@ #include "PluginsEnumerations.h" #include "PluginsJob.h" -#include +#include #include #include #define ERROR_MESSAGE_64BIT "A 64bit version of the Orthanc API is necessary" + namespace Orthanc { static void CopyToMemoryBuffer(OrthancPluginMemoryBuffer& target, @@ -918,7 +919,7 @@ boost::recursive_mutex changeCallbackMutex_; boost::mutex findCallbackMutex_; boost::mutex worklistCallbackMutex_; - boost::mutex decodeImageCallbackMutex_; + boost::shared_mutex decodeImageCallbackMutex_; // Changed from "boost::mutex" in Orthanc 1.7.0 boost::mutex jobsUnserializersMutex_; boost::mutex refreshMetricsMutex_; boost::mutex storageCommitmentScpMutex_; @@ -2109,7 +2110,7 @@ const _OrthancPluginDecodeImageCallback& p = *reinterpret_cast(parameters); - boost::mutex::scoped_lock lock(pimpl_->decodeImageCallbackMutex_); + boost::unique_lock lock(pimpl_->decodeImageCallbackMutex_); pimpl_->decodeImageCallbacks_.push_back(p.callback); LOG(INFO) << "Plugin has registered a callback to decode DICOM images (" @@ -2809,19 +2810,12 @@ case _OrthancPluginService_GetInstanceDecodedFrame: { - bool hasDecoderPlugin; - - { - boost::mutex::scoped_lock lock(pimpl_->decodeImageCallbackMutex_); - hasDecoderPlugin = !pimpl_->decodeImageCallbacks_.empty(); - } - std::unique_ptr decoded; if (p.targetImage == NULL) { throw OrthancException(ErrorCode_NullPointer); } - else if (hasDecoderPlugin) + else if (HasCustomImageDecoder()) { // TODO - This call could be speeded up the future, if a // "decoding context" gets introduced in the decoder plugins @@ -4826,7 +4820,7 @@ bool OrthancPlugins::HasCustomImageDecoder() { - boost::mutex::scoped_lock lock(pimpl_->decodeImageCallbackMutex_); + boost::shared_lock lock(pimpl_->decodeImageCallbackMutex_); return !pimpl_->decodeImageCallbacks_.empty(); } @@ -4835,7 +4829,7 @@ size_t size, unsigned int frame) { - boost::mutex::scoped_lock lock(pimpl_->decodeImageCallbackMutex_); + boost::shared_lock lock(pimpl_->decodeImageCallbackMutex_); for (PImpl::DecodeImageCallbacks::const_iterator decoder = pimpl_->decodeImageCallbacks_.begin();