changeset 802:f31f174d194b

fix the lifetime of the backend
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 10 Apr 2026 19:21:43 +0200
parents f9e4d92b0e97
children accca9ae6111
files Framework/Plugins/DatabaseBackendAdapterV4.cpp
diffstat 1 files changed, 37 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/Framework/Plugins/DatabaseBackendAdapterV4.cpp	Fri Apr 10 18:42:44 2026 +0200
+++ b/Framework/Plugins/DatabaseBackendAdapterV4.cpp	Fri Apr 10 19:21:43 2026 +0200
@@ -48,7 +48,9 @@
 namespace OrthancDatabases
 {
   static bool isBackendInUse_ = false;  // Only for sanity checks
-  static BaseIndexConnectionsPool* connectionPool_ = NULL;  // Only for the AuditLogHandler
+
+  // The AuditLogHandler necessitates the plugin to manage the resources associated with the pool of connections
+  static std::unique_ptr<BaseIndexConnectionsPool> connectionPool_;
 
   static Orthanc::DatabasePluginMessages::ResourceType Convert(OrthancPluginResourceType resourceType)
   {
@@ -1454,6 +1456,20 @@
                                             const void* requestData,
                                             uint64_t requestSize)
   {
+    if (rawPool == NULL ||
+        connectionPool_.get() == NULL ||
+        rawPool != connectionPool_.get())
+    {
+      LOG(ERROR) << "Internal error: Incorrect state for the pool of connections";
+      return OrthancPluginErrorCode_InternalError;
+    }
+
+    if (!isBackendInUse_)
+    {
+      LOG(ERROR) << "More than one index backend was registered, internal error";
+      return OrthancPluginErrorCode_InternalError;
+    }
+
     Orthanc::DatabasePluginMessages::Request request;
     if (!request.ParseFromArray(requestData, requestSize))
     {
@@ -1461,22 +1477,14 @@
       return OrthancPluginErrorCode_InternalError;
     }
 
-    if (rawPool == NULL)
-    {
-      LOG(ERROR) << "Received a NULL pointer from the database";
-      return OrthancPluginErrorCode_InternalError;
-    }
-
     try
     {
-      BaseIndexConnectionsPool& pool = *reinterpret_cast<BaseIndexConnectionsPool*>(rawPool);
-
       Orthanc::DatabasePluginMessages::Response response;
       
       switch (request.type())
       {
         case Orthanc::DatabasePluginMessages::REQUEST_DATABASE:
-          ProcessDatabaseOperation(*response.mutable_database_response(), request.database_request(), pool);
+          ProcessDatabaseOperation(*response.mutable_database_response(), request.database_request(), *connectionPool_);
           break;
           
         case Orthanc::DatabasePluginMessages::REQUEST_TRANSACTION:
@@ -1498,7 +1506,7 @@
         throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "Cannot serialize to protobuf");
       }
 
-      if (OrthancPluginCreateMemoryBuffer64(pool.GetContext(), serializedResponse, s.size()) != OrthancPluginErrorCode_Success)
+      if (OrthancPluginCreateMemoryBuffer64(connectionPool_->GetContext(), serializedResponse, s.size()) != OrthancPluginErrorCode_Success)
       {
         throw Orthanc::OrthancException(Orthanc::ErrorCode_NotEnoughMemory, "Cannot allocate a memory buffer");
       }
@@ -1537,26 +1545,23 @@
 
   static void FinalizeBackend(void* rawPool)
   {
-    if (rawPool != NULL)
+    if (rawPool == NULL ||
+        connectionPool_.get() == NULL ||
+        connectionPool_.get() != rawPool)
     {
-      BaseIndexConnectionsPool* pool = reinterpret_cast<BaseIndexConnectionsPool*>(rawPool);
-      
-      if (isBackendInUse_)
-      {
-        isBackendInUse_ = false;
-        connectionPool_ = NULL;
-      }
-      else
-      {
-        LOG(ERROR) << "More than one index backend was registered, internal error";
-      }
+      LOG(ERROR) << "Internal error: Incorrect state for the pool of connections";
+    }
 
-      delete pool;
+    if (isBackendInUse_)
+    {
+      isBackendInUse_ = false;
     }
     else
     {
-      LOG(ERROR) << "Received a null pointer from the Orthanc core, internal error";
+      LOG(ERROR) << "More than one index backend was registered, internal error";
     }
+
+    connectionPool_.reset(NULL);
   }
 
 
@@ -1569,7 +1574,7 @@
                                          uint32_t                  logDataSize)
   {
     if (!isBackendInUse_ ||
-        connectionPool_ == NULL)
+        connectionPool_.get() == NULL)
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
     }
@@ -1785,29 +1790,28 @@
                                           unsigned int maxDatabaseRetries,
                                           unsigned int housekeepingDelaySeconds)
   {
-    std::unique_ptr<BaseIndexConnectionsPool> pool;
-
+    // The "connectionPool_" takes the ownership of the backend
     if (useDynamicConnectionPool)
     {
-      pool.reset(new DynamicIndexConnectionsPool(backend, countConnections, housekeepingDelaySeconds));
+      connectionPool_.reset(new DynamicIndexConnectionsPool(backend, countConnections, housekeepingDelaySeconds));
     }
     else
     {
-      pool.reset(new IndexConnectionsPool(backend, countConnections, housekeepingDelaySeconds));
+      connectionPool_.reset(new IndexConnectionsPool(backend, countConnections, housekeepingDelaySeconds));
     }
     
     if (isBackendInUse_)
     {
+      connectionPool_.reset();  // This implies "delete backend"
       throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
     }
 
     OrthancPluginContext* context = backend->GetContext();
-    connectionPool_ = pool.get(); // we need to keep a pointer on the connectionPool for the static Audit log handler
  
-    if (OrthancPluginRegisterDatabaseBackendV4(context, pool.release(), maxDatabaseRetries,
+    if (OrthancPluginRegisterDatabaseBackendV4(context, connectionPool_.get(), maxDatabaseRetries,
                                                CallBackend, FinalizeBackend) != OrthancPluginErrorCode_Success)
     {
-      delete backend;
+      connectionPool_.reset();  // This implies "delete backend"
       throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "Unable to register the database backend");
     }