changeset 374:4a3985088723 db-protobuf

moved class IndexConnectionsPool out of DatabaseBackendAdapterV3
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 28 Mar 2023 14:51:17 +0200
parents be7de633695c
children 824d70ce85ff
files Framework/Plugins/DatabaseBackendAdapterV3.cpp Framework/Plugins/IndexConnectionsPool.cpp Framework/Plugins/IndexConnectionsPool.h Resources/CMake/DatabasesPluginConfiguration.cmake
diffstat 4 files changed, 280 insertions(+), 196 deletions(-) [+]
line wrap: on
line diff
--- a/Framework/Plugins/DatabaseBackendAdapterV3.cpp	Tue Mar 28 12:47:54 2023 +0200
+++ b/Framework/Plugins/DatabaseBackendAdapterV3.cpp	Tue Mar 28 14:51:17 2023 +0200
@@ -25,8 +25,9 @@
 #if defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE)         // Macro introduced in Orthanc 1.3.1
 #  if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 9, 2)
 
+#include "IndexConnectionsPool.h"
+
 #include <Logging.h>
-#include <MultiThreading/SharedMessageQueue.h>
 #include <OrthancException.h>
 
 #include <stdexcept>
@@ -82,172 +83,6 @@
   }
     
     
-  class DatabaseBackendAdapterV3::Adapter : public boost::noncopyable
-  {
-  private:
-    class ManagerReference : public Orthanc::IDynamicObject
-    {
-    private:
-      DatabaseManager*  manager_;
-
-    public:
-      ManagerReference(DatabaseManager& manager) :
-        manager_(&manager)
-      {
-      }
-
-      DatabaseManager& GetManager()
-      {
-        assert(manager_ != NULL);
-        return *manager_;
-      }
-    };
-    
-    std::unique_ptr<IndexBackend>  backend_;
-    OrthancPluginContext*          context_;
-    boost::shared_mutex            connectionsMutex_;
-    size_t                         countConnections_;
-    std::list<DatabaseManager*>    connections_;
-    Orthanc::SharedMessageQueue    availableConnections_;
-
-  public:
-    Adapter(IndexBackend* backend,
-            size_t countConnections) :
-      backend_(backend),
-      countConnections_(countConnections)
-    {
-      if (countConnections == 0)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange,
-                                        "There must be a non-zero number of connections to the database");
-      }
-      else if (backend == NULL)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
-      }
-      else
-      {
-        context_ = backend_->GetContext();
-      }
-    }
-
-    ~Adapter()
-    {
-      for (std::list<DatabaseManager*>::iterator
-             it = connections_.begin(); it != connections_.end(); ++it)
-      {
-        assert(*it != NULL);
-        delete *it;
-      }
-    }
-
-    OrthancPluginContext* GetContext() const
-    {
-      return context_;
-    }
-
-    void OpenConnections()
-    {
-      boost::unique_lock<boost::shared_mutex>  lock(connectionsMutex_);
-
-      if (connections_.size() == 0)
-      {
-        assert(backend_.get() != NULL);
-
-        {
-          std::unique_ptr<DatabaseManager> manager(new DatabaseManager(backend_->CreateDatabaseFactory()));
-          manager->GetDatabase();  // Make sure to open the database connection
-          
-          backend_->ConfigureDatabase(*manager);
-          connections_.push_back(manager.release());
-        }
-
-        for (size_t i = 1; i < countConnections_; i++)
-        {
-          connections_.push_back(new DatabaseManager(backend_->CreateDatabaseFactory()));
-          connections_.back()->GetDatabase();  // Make sure to open the database connection
-        }
-
-        for (std::list<DatabaseManager*>::iterator
-               it = connections_.begin(); it != connections_.end(); ++it)
-        {
-          assert(*it != NULL);
-          availableConnections_.Enqueue(new ManagerReference(**it));
-        }        
-      }
-      else
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-    }
-
-    void CloseConnections()
-    {
-      boost::unique_lock<boost::shared_mutex>  lock(connectionsMutex_);
-
-      if (connections_.size() != countConnections_)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-      else if (availableConnections_.GetSize() != countConnections_)
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_Database, "Some connections are still in use, bug in the Orthanc core");
-      }
-      else
-      {
-        for (std::list<DatabaseManager*>::iterator
-               it = connections_.begin(); it != connections_.end(); ++it)
-        {
-          assert(*it != NULL);
-          (*it)->Close();
-        }
-      }
-    }
-
-    class DatabaseAccessor : public boost::noncopyable
-    {
-    private:
-      boost::shared_lock<boost::shared_mutex>  lock_;
-      Adapter&                                 adapter_;
-      DatabaseManager*                         manager_;
-      
-    public:
-      DatabaseAccessor(Adapter& adapter) :
-        lock_(adapter.connectionsMutex_),
-        adapter_(adapter),
-        manager_(NULL)
-      {
-        for (;;)
-        {
-          std::unique_ptr<Orthanc::IDynamicObject> manager(adapter.availableConnections_.Dequeue(100));
-          if (manager.get() != NULL)
-          {
-            manager_ = &dynamic_cast<ManagerReference&>(*manager).GetManager();
-            return;
-          }
-        }
-      }
-
-      ~DatabaseAccessor()
-      {
-        assert(manager_ != NULL);
-        adapter_.availableConnections_.Enqueue(new ManagerReference(*manager_));
-      }
-
-      IndexBackend& GetBackend() const
-      {
-        return *adapter_.backend_;
-      }
-
-      DatabaseManager& GetManager() const
-      {
-        assert(manager_ != NULL);
-        return *manager_;
-      }
-    };
-  };
-
-
   class DatabaseBackendAdapterV3::Output : public IDatabaseBackendOutput
   {
   private:
@@ -802,14 +637,14 @@
   class DatabaseBackendAdapterV3::Transaction : public boost::noncopyable
   {
   private:
-    Adapter&   adapter_;
-    std::unique_ptr<Adapter::DatabaseAccessor>  accessor_;
-    std::unique_ptr<Output>    output_;
+    IndexConnectionsPool&                            pool_;
+    std::unique_ptr<IndexConnectionsPool::Accessor>  accessor_;
+    std::unique_ptr<Output>                          output_;
     
   public:
-    Transaction(Adapter& adapter) :
-      adapter_(adapter),
-      accessor_(new Adapter::DatabaseAccessor(adapter)),
+    Transaction(IndexConnectionsPool& pool) :
+      pool_(pool),
+      accessor_(new IndexConnectionsPool::Accessor(pool)),
       output_(new Output)
     {
     }
@@ -961,35 +796,35 @@
     
   static OrthancPluginErrorCode Open(void* database)
   {
-    DatabaseBackendAdapterV3::Adapter* adapter = reinterpret_cast<DatabaseBackendAdapterV3::Adapter*>(database);
+    IndexConnectionsPool* pool = reinterpret_cast<IndexConnectionsPool*>(database);
 
     try
     {
-      adapter->OpenConnections();
+      pool->OpenConnections();
       return OrthancPluginErrorCode_Success;
     }
-    ORTHANC_PLUGINS_DATABASE_CATCH(adapter->GetContext());
+    ORTHANC_PLUGINS_DATABASE_CATCH(pool->GetContext());
   }
 
   
   static OrthancPluginErrorCode Close(void* database)
   {
-    DatabaseBackendAdapterV3::Adapter* adapter = reinterpret_cast<DatabaseBackendAdapterV3::Adapter*>(database);
+    IndexConnectionsPool* pool = reinterpret_cast<IndexConnectionsPool*>(database);
 
     try
     {
-      adapter->CloseConnections();
+      pool->CloseConnections();
       return OrthancPluginErrorCode_Success;
     }
-    ORTHANC_PLUGINS_DATABASE_CATCH(adapter->GetContext());
+    ORTHANC_PLUGINS_DATABASE_CATCH(pool->GetContext());
   }
 
   
   static OrthancPluginErrorCode DestructDatabase(void* database)
   {
-    DatabaseBackendAdapterV3::Adapter* adapter = reinterpret_cast<DatabaseBackendAdapterV3::Adapter*>(database);
+    IndexConnectionsPool* pool = reinterpret_cast<IndexConnectionsPool*>(database);
 
-    if (adapter == NULL)
+    if (pool == NULL)
     {
       return OrthancPluginErrorCode_InternalError;
     }
@@ -1001,10 +836,10 @@
       }
       else
       {
-        OrthancPluginLogError(adapter->GetContext(), "More than one index backend was registered, internal error");
+        OrthancPluginLogError(pool->GetContext(), "More than one index backend was registered, internal error");
       }
       
-      delete adapter;
+      delete pool;
 
       return OrthancPluginErrorCode_Success;
     }
@@ -1014,15 +849,15 @@
   static OrthancPluginErrorCode GetDatabaseVersion(void* database,
                                                    uint32_t* version)
   {
-    DatabaseBackendAdapterV3::Adapter* adapter = reinterpret_cast<DatabaseBackendAdapterV3::Adapter*>(database);
+    IndexConnectionsPool* pool = reinterpret_cast<IndexConnectionsPool*>(database);
       
     try
     {
-      DatabaseBackendAdapterV3::Adapter::DatabaseAccessor accessor(*adapter);
+      IndexConnectionsPool::Accessor accessor(*pool);
       *version = accessor.GetBackend().GetDatabaseVersion(accessor.GetManager());
       return OrthancPluginErrorCode_Success;
     }
-    ORTHANC_PLUGINS_DATABASE_CATCH(adapter->GetContext());
+    ORTHANC_PLUGINS_DATABASE_CATCH(pool->GetContext());
   }
 
 
@@ -1030,30 +865,30 @@
                                                 OrthancPluginStorageArea* storageArea,
                                                 uint32_t  targetVersion)
   {
-    DatabaseBackendAdapterV3::Adapter* adapter = reinterpret_cast<DatabaseBackendAdapterV3::Adapter*>(database);
+    IndexConnectionsPool* pool = reinterpret_cast<IndexConnectionsPool*>(database);
       
     try
     {
-      DatabaseBackendAdapterV3::Adapter::DatabaseAccessor accessor(*adapter);
+      IndexConnectionsPool::Accessor accessor(*pool);
       accessor.GetBackend().UpgradeDatabase(accessor.GetManager(), targetVersion, storageArea);
       return OrthancPluginErrorCode_Success;
     }
-    ORTHANC_PLUGINS_DATABASE_CATCH(adapter->GetContext());
+    ORTHANC_PLUGINS_DATABASE_CATCH(pool->GetContext());
   }
 
 
   static OrthancPluginErrorCode HasRevisionsSupport(void* database,
                                                     uint8_t* target)
   {
-    DatabaseBackendAdapterV3::Adapter* adapter = reinterpret_cast<DatabaseBackendAdapterV3::Adapter*>(database);
+    IndexConnectionsPool* pool = reinterpret_cast<IndexConnectionsPool*>(database);
       
     try
     {
-      DatabaseBackendAdapterV3::Adapter::DatabaseAccessor accessor(*adapter);
+      IndexConnectionsPool::Accessor accessor(*pool);
       *target = (accessor.GetBackend().HasRevisionsSupport() ? 1 : 0);
       return OrthancPluginErrorCode_Success;
     }
-    ORTHANC_PLUGINS_DATABASE_CATCH(adapter->GetContext());
+    ORTHANC_PLUGINS_DATABASE_CATCH(pool->GetContext());
   }
 
 
@@ -1061,11 +896,11 @@
                                                  OrthancPluginDatabaseTransaction** target /* out */,
                                                  OrthancPluginDatabaseTransactionType type)
   {
-    DatabaseBackendAdapterV3::Adapter* adapter = reinterpret_cast<DatabaseBackendAdapterV3::Adapter*>(database);
+    IndexConnectionsPool* pool = reinterpret_cast<IndexConnectionsPool*>(database);
       
     try
     {
-      std::unique_ptr<DatabaseBackendAdapterV3::Transaction> transaction(new DatabaseBackendAdapterV3::Transaction(*adapter));
+      std::unique_ptr<DatabaseBackendAdapterV3::Transaction> transaction(new DatabaseBackendAdapterV3::Transaction(*pool));
       
       switch (type)
       {
@@ -1085,7 +920,7 @@
       
       return OrthancPluginErrorCode_Success;
     }
-    ORTHANC_PLUGINS_DATABASE_CATCH(adapter->GetContext());
+    ORTHANC_PLUGINS_DATABASE_CATCH(pool->GetContext());
   }
 
   
@@ -2077,7 +1912,7 @@
  
     if (OrthancPluginRegisterDatabaseBackendV3(
           context, &params, sizeof(params), maxDatabaseRetries,
-          new Adapter(protection.release(), countConnections)) != OrthancPluginErrorCode_Success)
+          new IndexConnectionsPool(protection.release(), countConnections)) != OrthancPluginErrorCode_Success)
     {
       delete backend;
       throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "Unable to register the database backend");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Plugins/IndexConnectionsPool.cpp	Tue Mar 28 14:51:17 2023 +0200
@@ -0,0 +1,173 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2022 Osimis S.A., Belgium
+ * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "IndexConnectionsPool.h"
+
+namespace OrthancDatabases
+{
+  class IndexConnectionsPool::ManagerReference : public Orthanc::IDynamicObject
+  {
+  private:
+    DatabaseManager*  manager_;
+
+  public:
+    ManagerReference(DatabaseManager& manager) :
+      manager_(&manager)
+    {
+    }
+
+    DatabaseManager& GetManager()
+    {
+      assert(manager_ != NULL);
+      return *manager_;
+    }
+  };
+
+
+  IndexConnectionsPool::IndexConnectionsPool(IndexBackend* backend,
+                                             size_t countConnections) :
+    backend_(backend),
+    countConnections_(countConnections)
+  {
+    if (countConnections == 0)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange,
+                                      "There must be a non-zero number of connections to the database");
+    }
+    else if (backend == NULL)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+    }
+    else
+    {
+      context_ = backend_->GetContext();
+    }
+  }
+
+  
+  IndexConnectionsPool::~IndexConnectionsPool()
+  {
+    for (std::list<DatabaseManager*>::iterator
+           it = connections_.begin(); it != connections_.end(); ++it)
+    {
+      assert(*it != NULL);
+      delete *it;
+    }
+  }
+
+
+  void IndexConnectionsPool::OpenConnections()
+  {
+    boost::unique_lock<boost::shared_mutex>  lock(connectionsMutex_);
+
+    if (connections_.size() == 0)
+    {
+      assert(backend_.get() != NULL);
+
+      {
+        std::unique_ptr<DatabaseManager> manager(new DatabaseManager(backend_->CreateDatabaseFactory()));
+        manager->GetDatabase();  // Make sure to open the database connection
+          
+        backend_->ConfigureDatabase(*manager);
+        connections_.push_back(manager.release());
+      }
+
+      for (size_t i = 1; i < countConnections_; i++)
+      {
+        connections_.push_back(new DatabaseManager(backend_->CreateDatabaseFactory()));
+        connections_.back()->GetDatabase();  // Make sure to open the database connection
+      }
+
+      for (std::list<DatabaseManager*>::iterator
+             it = connections_.begin(); it != connections_.end(); ++it)
+      {
+        assert(*it != NULL);
+        availableConnections_.Enqueue(new ManagerReference(**it));
+      }        
+    }
+    else
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+  }
+
+
+  void IndexConnectionsPool::CloseConnections()
+  {
+    boost::unique_lock<boost::shared_mutex>  lock(connectionsMutex_);
+
+    if (connections_.size() != countConnections_)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
+    }
+    else if (availableConnections_.GetSize() != countConnections_)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_Database, "Some connections are still in use, bug in the Orthanc core");
+    }
+    else
+    {
+      for (std::list<DatabaseManager*>::iterator
+             it = connections_.begin(); it != connections_.end(); ++it)
+      {
+        assert(*it != NULL);
+        (*it)->Close();
+      }
+    }
+  }
+
+
+  IndexConnectionsPool::Accessor::Accessor(IndexConnectionsPool& pool) :
+    lock_(pool.connectionsMutex_),
+    pool_(pool),
+    manager_(NULL)
+  {
+    for (;;)
+    {
+      std::unique_ptr<Orthanc::IDynamicObject> manager(pool.availableConnections_.Dequeue(100));
+      if (manager.get() != NULL)
+      {
+        manager_ = &dynamic_cast<ManagerReference&>(*manager).GetManager();
+        return;
+      }
+    }
+  }
+
+  
+  IndexConnectionsPool::Accessor::~Accessor()
+  {
+    assert(manager_ != NULL);
+    pool_.availableConnections_.Enqueue(new ManagerReference(*manager_));
+  }
+
+  
+  IndexBackend& IndexConnectionsPool::Accessor::GetBackend() const
+  {
+    return *pool_.backend_;
+  }
+
+  
+  DatabaseManager& IndexConnectionsPool::Accessor::GetManager() const
+  {
+    assert(manager_ != NULL);
+    return *manager_;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Plugins/IndexConnectionsPool.h	Tue Mar 28 14:51:17 2023 +0200
@@ -0,0 +1,75 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2022 Osimis S.A., Belgium
+ * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "IndexBackend.h"
+
+#include <MultiThreading/SharedMessageQueue.h>
+
+namespace OrthancDatabases
+{
+  class IndexConnectionsPool : public boost::noncopyable
+  {
+  private:
+    class ManagerReference;
+
+    std::unique_ptr<IndexBackend>  backend_;
+    OrthancPluginContext*          context_;
+    boost::shared_mutex            connectionsMutex_;
+    size_t                         countConnections_;
+    std::list<DatabaseManager*>    connections_;
+    Orthanc::SharedMessageQueue    availableConnections_;
+
+  public:
+    IndexConnectionsPool(IndexBackend* backend,
+                         size_t countConnections);
+
+    ~IndexConnectionsPool();
+
+    OrthancPluginContext* GetContext() const
+    {
+      return context_;
+    }
+
+    void OpenConnections();
+
+    void CloseConnections();
+
+    class Accessor : public boost::noncopyable
+    {
+    private:
+      boost::shared_lock<boost::shared_mutex>  lock_;
+      IndexConnectionsPool&                    pool_;
+      DatabaseManager*                         manager_;
+      
+    public:
+      Accessor(IndexConnectionsPool& pool);
+
+      ~Accessor();
+
+      IndexBackend& GetBackend() const;
+
+      DatabaseManager& GetManager() const;
+    };
+  };
+}
--- a/Resources/CMake/DatabasesPluginConfiguration.cmake	Tue Mar 28 12:47:54 2023 +0200
+++ b/Resources/CMake/DatabasesPluginConfiguration.cmake	Tue Mar 28 14:51:17 2023 +0200
@@ -94,6 +94,7 @@
   ${ORTHANC_DATABASES_ROOT}/Framework/Plugins/DatabaseBackendAdapterV3.cpp
   ${ORTHANC_DATABASES_ROOT}/Framework/Plugins/DatabaseBackendAdapterV4.cpp
   ${ORTHANC_DATABASES_ROOT}/Framework/Plugins/IndexBackend.cpp
+  ${ORTHANC_DATABASES_ROOT}/Framework/Plugins/IndexConnectionsPool.cpp
   ${ORTHANC_DATABASES_ROOT}/Framework/Plugins/StorageBackend.cpp
   ${ORTHANC_DATABASES_ROOT}/Resources/Orthanc/Databases/DatabaseConstraint.cpp
   ${ORTHANC_DATABASES_ROOT}/Resources/Orthanc/Databases/ISqlLookupFormatter.cpp