# HG changeset patch # User Alain Mazy # Date 1699428887 -3600 # Node ID ca9cf4d46883caf49682ccc8d789c6f3bc579247 # Parent 16cbfefa15e9704baf2129cf678ce69e42904e4c ServerContextLock transformed into ServerContextReference /usr/bin/env /bin/sh /tmp/Microsoft-MIEngine-Cmd-owukncoo.ob4 diff -r 16cbfefa15e9 -r ca9cf4d46883 NEWS --- a/NEWS Tue Nov 07 12:52:37 2023 +0100 +++ b/NEWS Wed Nov 08 08:34:47 2023 +0100 @@ -4,6 +4,10 @@ General ------- +* Performance: + - Allow multiple plugins to use the plugin SDK at the same time. In previous versions, + functions like instance transcoding or instance reading where mutually exclusive. + This can bring some significant improvements particularly in viewers. * Housekeeper plugin: - Update to rebuild the cache of the DicomWeb plugin when updating to DicomWeb 1.15. - New trigger configuration: "DicomWebCacheChange" diff -r 16cbfefa15e9 -r ca9cf4d46883 OrthancServer/Plugins/Engine/OrthancPlugins.cpp --- a/OrthancServer/Plugins/Engine/OrthancPlugins.cpp Tue Nov 07 12:52:37 2023 +0100 +++ b/OrthancServer/Plugins/Engine/OrthancPlugins.cpp Wed Nov 08 08:34:47 2023 +0100 @@ -1090,7 +1090,10 @@ class OrthancPlugins::PImpl { private: - boost::mutex contextMutex_; + boost::mutex contextMutex_; + boost::condition_variable contextCond_; + size_t contextRefCount_; + ServerContext* context_; public: @@ -1458,21 +1461,38 @@ }; - class ServerContextLock + // This class ensures that the Context remains valid while being used. + // But it does not prevent multiple users to use the context at the same time. + // (new behavior in 1.12.2. In previous version, only one user could use the "locked" context) + class ServerContextReference { private: - boost::mutex::scoped_lock lock_; ServerContext* context_; + boost::mutex& mutex_; + boost::condition_variable& cond_; + size_t& refCount_; public: - explicit ServerContextLock(PImpl& that) : - lock_(that.contextMutex_), - context_(that.context_) + explicit ServerContextReference(PImpl& that) : + context_(that.context_), + mutex_(that.contextMutex_), + cond_(that.contextCond_), + refCount_(that.contextRefCount_) { if (context_ == NULL) { throw OrthancException(ErrorCode_DatabaseNotInitialized); } + + boost::mutex::scoped_lock lock(mutex_); + refCount_++; + } + + ~ServerContextReference() + { + boost::mutex::scoped_lock lock(mutex_); + refCount_++; + cond_.notify_one(); } ServerContext& GetContext() @@ -1485,7 +1505,13 @@ void SetServerContext(ServerContext* context) { + // update only the context while nobody is using it boost::mutex::scoped_lock lock(contextMutex_); + + while (contextRefCount_ > 0) + { + contextCond_.wait(lock); + } context_ = context; } @@ -1554,6 +1580,7 @@ unsigned int maxDatabaseRetries_; // New in Orthanc 1.9.2 explicit PImpl(const std::string& databaseServerIdentifier) : + contextRefCount_(0), context_(NULL), findCallback_(NULL), worklistCallback_(NULL), @@ -1600,7 +1627,7 @@ { static const char* LUA_CALLBACK = "IncomingWorklistRequestFilter"; - PImpl::ServerContextLock lock(*that_.pimpl_); + PImpl::ServerContextReference lock(*that_.pimpl_); LuaScripting::Lock lua(lock.GetContext().GetLuaScripting()); if (!lua.GetLua().IsExistingFunction(LUA_CALLBACK)) @@ -3156,7 +3183,7 @@ std::string dicom; { - PImpl::ServerContextLock lock(*pimpl_); + PImpl::ServerContextReference lock(*pimpl_); lock.GetContext().ReadDicom(dicom, p.instanceId); } @@ -3197,7 +3224,7 @@ IHttpHandler* handler; { - PImpl::ServerContextLock lock(*pimpl_); + PImpl::ServerContextReference lock(*pimpl_); handler = &lock.GetContext().GetHttpHandler().RestrictToOrthancRestApi(!afterPlugins); } @@ -3230,7 +3257,7 @@ IHttpHandler* handler; { - PImpl::ServerContextLock lock(*pimpl_); + PImpl::ServerContextReference lock(*pimpl_); handler = &lock.GetContext().GetHttpHandler().RestrictToOrthancRestApi(!p.afterPlugins); } @@ -3254,7 +3281,7 @@ IHttpHandler* handler; { - PImpl::ServerContextLock lock(*pimpl_); + PImpl::ServerContextReference lock(*pimpl_); handler = &lock.GetContext().GetHttpHandler().RestrictToOrthancRestApi(!afterPlugins); } @@ -3281,7 +3308,7 @@ IHttpHandler* handler; { - PImpl::ServerContextLock lock(*pimpl_); + PImpl::ServerContextReference lock(*pimpl_); handler = &lock.GetContext().GetHttpHandler().RestrictToOrthancRestApi(!afterPlugins); } @@ -3340,7 +3367,7 @@ std::vector result; { - PImpl::ServerContextLock lock(*pimpl_); + PImpl::ServerContextReference lock(*pimpl_); lock.GetContext().GetIndex().LookupIdentifierExact(result, level, tag, p.argument); } @@ -3635,7 +3662,7 @@ std::unique_ptr decoded; { - PImpl::ServerContextLock lock(*pimpl_); + PImpl::ServerContextReference lock(*pimpl_); decoded.reset(lock.GetContext().DecodeDicomFrame(instance, p.frameIndex)); } @@ -3718,7 +3745,7 @@ case OrthancPluginImageFormat_Dicom: { - PImpl::ServerContextLock lock(*pimpl_); + PImpl::ServerContextReference lock(*pimpl_); image.reset(lock.GetContext().DecodeDicomFrame(p.data, p.size, 0)); break; } @@ -4043,7 +4070,7 @@ IHttpHandler* handler; { - PImpl::ServerContextLock lock(*pimpl_); + PImpl::ServerContextReference lock(*pimpl_); handler = &lock.GetContext().GetHttpHandler().RestrictToOrthancRestApi(!p.afterPlugins); } @@ -4265,7 +4292,7 @@ std::string content; { - PImpl::ServerContextLock lock(*pimpl_); + PImpl::ServerContextReference lock(*pimpl_); lock.GetContext().ReadDicom(content, p.instanceId); } @@ -4394,7 +4421,7 @@ case _OrthancPluginService_DecodeDicomImage: { - PImpl::ServerContextLock lock(*pimpl_); + PImpl::ServerContextReference lock(*pimpl_); result.reset(lock.GetContext().DecodeDicomFrame(p.constBuffer, p.bufferSize, p.frameIndex)); break; } @@ -4447,7 +4474,7 @@ std::string buffer; { - PImpl::ServerContextLock lock(*pimpl_); + PImpl::ServerContextReference lock(*pimpl_); lock.GetContext().ReadDicom(buffer, params.instanceId); } @@ -4464,7 +4491,7 @@ std::string buffer; { - PImpl::ServerContextLock lock(*pimpl_); + PImpl::ServerContextReference lock(*pimpl_); if (!lock.GetContext().ReadDicomUntilPixelData(buffer, params.instanceId)) { lock.GetContext().ReadDicom(buffer, params.instanceId); @@ -4482,7 +4509,7 @@ ValueRepresentation pixelDataVR = parsed->GuessPixelDataValueRepresentation(); { - PImpl::ServerContextLock lock(*pimpl_); + PImpl::ServerContextReference lock(*pimpl_); std::string s; int64_t revision; // unused @@ -4813,7 +4840,7 @@ { // TODO - Plugins can only access global properties of their // own Orthanc server (no access to the shared global properties) - PImpl::ServerContextLock lock(*pimpl_); + PImpl::ServerContextReference lock(*pimpl_); lock.GetContext().GetIndex().SetGlobalProperty(static_cast(p.property), false /* not shared */, p.value); return true; @@ -4830,7 +4857,7 @@ { // TODO - Plugins can only access global properties of their // own Orthanc server (no access to the shared global properties) - PImpl::ServerContextLock lock(*pimpl_); + PImpl::ServerContextReference lock(*pimpl_); result = lock.GetContext().GetIndex().GetGlobalProperty(static_cast(p.property), false /* not shared */, p.value); } @@ -5297,7 +5324,7 @@ std::string uuid; - PImpl::ServerContextLock lock(*pimpl_); + PImpl::ServerContextReference lock(*pimpl_); lock.GetContext().GetJobsEngine().GetRegistry().Submit (uuid, reinterpret_cast(p.job), p.priority); @@ -5320,7 +5347,7 @@ *reinterpret_cast(parameters); { - PImpl::ServerContextLock lock(*pimpl_); + PImpl::ServerContextReference lock(*pimpl_); lock.GetContext().GetMetricsRegistry().SetFloatValue(p.name, p.value, Plugins::Convert(p.type)); } @@ -5333,7 +5360,7 @@ *reinterpret_cast(parameters); { - PImpl::ServerContextLock lock(*pimpl_); + PImpl::ServerContextReference lock(*pimpl_); lock.GetContext().GetMetricsRegistry().SetIntegerValue(p.name, p.value, Plugins::Convert(p.type)); } @@ -5425,7 +5452,7 @@ bool success; { - PImpl::ServerContextLock lock(*pimpl_); + PImpl::ServerContextReference lock(*pimpl_); success = lock.GetContext().Transcode( transcoded, source, syntaxes, true /* allow new sop */); } diff -r 16cbfefa15e9 -r ca9cf4d46883 OrthancServer/Sources/main.cpp --- a/OrthancServer/Sources/main.cpp Tue Nov 07 12:52:37 2023 +0100 +++ b/OrthancServer/Sources/main.cpp Wed Nov 08 08:34:47 2023 +0100 @@ -1606,6 +1606,7 @@ lock.GetConfiguration().LoadModalitiesAndPeers(); } + // this function exits only when Orthanc stops or resets return ConfigureHttpHandler(context, plugins, loadJobsFromDatabase); } }