# HG changeset patch # User Sebastien Jodogne # Date 1680007877 -7200 # Node ID 4a39850887232d6dbc240f4e64d92ac63b3f741f # Parent be7de633695c6a051e9952439285ba33924a19a2 moved class IndexConnectionsPool out of DatabaseBackendAdapterV3 diff -r be7de633695c -r 4a3985088723 Framework/Plugins/DatabaseBackendAdapterV3.cpp --- 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 -#include #include #include @@ -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 backend_; - OrthancPluginContext* context_; - boost::shared_mutex connectionsMutex_; - size_t countConnections_; - std::list 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::iterator - it = connections_.begin(); it != connections_.end(); ++it) - { - assert(*it != NULL); - delete *it; - } - } - - OrthancPluginContext* GetContext() const - { - return context_; - } - - void OpenConnections() - { - boost::unique_lock lock(connectionsMutex_); - - if (connections_.size() == 0) - { - assert(backend_.get() != NULL); - - { - std::unique_ptr 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::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 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::iterator - it = connections_.begin(); it != connections_.end(); ++it) - { - assert(*it != NULL); - (*it)->Close(); - } - } - } - - class DatabaseAccessor : public boost::noncopyable - { - private: - boost::shared_lock lock_; - Adapter& adapter_; - DatabaseManager* manager_; - - public: - DatabaseAccessor(Adapter& adapter) : - lock_(adapter.connectionsMutex_), - adapter_(adapter), - manager_(NULL) - { - for (;;) - { - std::unique_ptr manager(adapter.availableConnections_.Dequeue(100)); - if (manager.get() != NULL) - { - manager_ = &dynamic_cast(*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 accessor_; - std::unique_ptr output_; + IndexConnectionsPool& pool_; + std::unique_ptr accessor_; + std::unique_ptr 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(database); + IndexConnectionsPool* pool = reinterpret_cast(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(database); + IndexConnectionsPool* pool = reinterpret_cast(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(database); + IndexConnectionsPool* pool = reinterpret_cast(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(database); + IndexConnectionsPool* pool = reinterpret_cast(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(database); + IndexConnectionsPool* pool = reinterpret_cast(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(database); + IndexConnectionsPool* pool = reinterpret_cast(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(database); + IndexConnectionsPool* pool = reinterpret_cast(database); try { - std::unique_ptr transaction(new DatabaseBackendAdapterV3::Transaction(*adapter)); + std::unique_ptr 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, ¶ms, 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"); diff -r be7de633695c -r 4a3985088723 Framework/Plugins/IndexConnectionsPool.cpp --- /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 . + **/ + + +#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::iterator + it = connections_.begin(); it != connections_.end(); ++it) + { + assert(*it != NULL); + delete *it; + } + } + + + void IndexConnectionsPool::OpenConnections() + { + boost::unique_lock lock(connectionsMutex_); + + if (connections_.size() == 0) + { + assert(backend_.get() != NULL); + + { + std::unique_ptr 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::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 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::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 manager(pool.availableConnections_.Dequeue(100)); + if (manager.get() != NULL) + { + manager_ = &dynamic_cast(*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_; + } +} diff -r be7de633695c -r 4a3985088723 Framework/Plugins/IndexConnectionsPool.h --- /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 . + **/ + + +#pragma once + +#include "IndexBackend.h" + +#include + +namespace OrthancDatabases +{ + class IndexConnectionsPool : public boost::noncopyable + { + private: + class ManagerReference; + + std::unique_ptr backend_; + OrthancPluginContext* context_; + boost::shared_mutex connectionsMutex_; + size_t countConnections_; + std::list 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 lock_; + IndexConnectionsPool& pool_; + DatabaseManager* manager_; + + public: + Accessor(IndexConnectionsPool& pool); + + ~Accessor(); + + IndexBackend& GetBackend() const; + + DatabaseManager& GetManager() const; + }; + }; +} diff -r be7de633695c -r 4a3985088723 Resources/CMake/DatabasesPluginConfiguration.cmake --- 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