Mercurial > hg > orthanc
changeset 5459:46ed738c3e5d pg-transactions
merge default -> pg-transactions
author | Alain Mazy <am@osimis.io> |
---|---|
date | Fri, 08 Dec 2023 10:27:24 +0100 |
parents | 06eb8bc9f024 (diff) d7c9c85d78dc (current diff) |
children | 38f1d06875ad |
files | OrthancServer/Sources/main.cpp |
diffstat | 15 files changed, 271 insertions(+), 155 deletions(-) [+] |
line wrap: on
line diff
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabase.cpp Fri Dec 08 10:26:53 2023 +0100 +++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabase.cpp Fri Dec 08 10:27:24 2023 +0100 @@ -43,7 +43,7 @@ namespace Orthanc { class OrthancPluginDatabase::Transaction : - public IDatabaseWrapper::ITransaction, + public BaseDatabaseWrapper::BaseTransaction, public Compatibility::ICreateInstance, public Compatibility::IGetChildrenMetadata, public Compatibility::ILookupResources, @@ -243,6 +243,11 @@ that_.activeTransaction_ = NULL; } + virtual const IDatabaseWrapper::Capabilities& GetDatabaseCapabilities() const ORTHANC_OVERRIDE + { + return that_.GetDatabaseCapabilities(); + } + IDatabaseListener& GetDatabaseListener() const { return listener_; @@ -1472,7 +1477,8 @@ payload_(payload), activeTransaction_(NULL), fastGetTotalSize_(false), - currentDiskSize_(0) + currentDiskSize_(0), + dbCapabilities_(false, false, false, false) { static const char* const MISSING = " Missing extension in database index plugin: ";
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabase.h Fri Dec 08 10:26:53 2023 +0100 +++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabase.h Fri Dec 08 10:27:24 2023 +0100 @@ -25,7 +25,7 @@ #if ORTHANC_ENABLE_PLUGINS == 1 #include "../../../OrthancFramework/Sources/SharedLibrary.h" -#include "../../Sources/Database/IDatabaseWrapper.h" +#include "../../Sources/Database/BaseDatabaseWrapper.h" #include "../Include/orthanc/OrthancCDatabasePlugin.h" #include "PluginsErrorDictionary.h" @@ -45,7 +45,7 @@ * able to rollback the modifications. Read-only accesses didn't * start a transaction, as they were protected by the global mutex. **/ - class OrthancPluginDatabase : public IDatabaseWrapper + class OrthancPluginDatabase : public BaseDatabaseWrapper { private: class Transaction; @@ -65,6 +65,7 @@ Transaction* activeTransaction_; bool fastGetTotalSize_; uint64_t currentDiskSize_; + IDatabaseWrapper::Capabilities dbCapabilities_; OrthancPluginDatabaseContext* GetContext() { @@ -94,11 +95,6 @@ { } - virtual bool HasFlushToDisk() const ORTHANC_OVERRIDE - { - return false; - } - virtual IDatabaseWrapper::ITransaction* StartTransaction(TransactionType type, IDatabaseListener& listener) ORTHANC_OVERRIDE; @@ -108,15 +104,11 @@ virtual void Upgrade(unsigned int targetVersion, IStorageArea& storageArea) ORTHANC_OVERRIDE; - virtual bool HasRevisionsSupport() const ORTHANC_OVERRIDE + const IDatabaseWrapper::Capabilities& GetDatabaseCapabilities() const ORTHANC_OVERRIDE { - return false; // No support for revisions in old API + return dbCapabilities_; } - virtual bool HasLabelsSupport() const ORTHANC_OVERRIDE - { - return false; - } void AnswerReceived(const _OrthancPluginDatabaseAnswer& answer); };
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.cpp Fri Dec 08 10:26:53 2023 +0100 +++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.cpp Fri Dec 08 10:27:24 2023 +0100 @@ -45,7 +45,7 @@ namespace Orthanc { - class OrthancPluginDatabaseV3::Transaction : public IDatabaseWrapper::ITransaction + class OrthancPluginDatabaseV3::Transaction : public BaseDatabaseWrapper::BaseTransaction { private: OrthancPluginDatabaseV3& that_; @@ -278,6 +278,10 @@ } } + virtual const IDatabaseWrapper::Capabilities& GetDatabaseCapabilities() const ORTHANC_OVERRIDE + { + return that_.GetDatabaseCapabilities(); + } virtual void Rollback() ORTHANC_OVERRIDE { @@ -1083,7 +1087,8 @@ library_(library), errorDictionary_(errorDictionary), database_(database), - serverIdentifier_(serverIdentifier) + serverIdentifier_(serverIdentifier), + dbCapabilities_(false, false /* revision support is updated in open() */, false, false) { CLOG(INFO, PLUGINS) << "Identifier of this Orthanc server for the global properties " << "of the custom database: \"" << serverIdentifier << "\""; @@ -1190,6 +1195,11 @@ void OrthancPluginDatabaseV3::Open() { CheckSuccess(backend_.open(database_)); + + // update the db capabilities + uint8_t hasRevisions; + CheckSuccess(backend_.hasRevisionsSupport(database_, &hasRevisions)); + dbCapabilities_.hasRevisionsSupport_ = (hasRevisions != 0); } @@ -1250,12 +1260,4 @@ } } - - bool OrthancPluginDatabaseV3::HasRevisionsSupport() const - { - // WARNING: This method requires "Open()" to have been called - uint8_t hasRevisions; - CheckSuccess(backend_.hasRevisionsSupport(database_, &hasRevisions)); - return (hasRevisions != 0); - } }
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.h Fri Dec 08 10:26:53 2023 +0100 +++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.h Fri Dec 08 10:27:24 2023 +0100 @@ -25,13 +25,13 @@ #if ORTHANC_ENABLE_PLUGINS == 1 #include "../../../OrthancFramework/Sources/SharedLibrary.h" -#include "../../Sources/Database/IDatabaseWrapper.h" +#include "../../Sources/Database/BaseDatabaseWrapper.h" #include "../Include/orthanc/OrthancCDatabasePlugin.h" #include "PluginsErrorDictionary.h" namespace Orthanc { - class OrthancPluginDatabaseV3 : public IDatabaseWrapper + class OrthancPluginDatabaseV3 : public BaseDatabaseWrapper { private: class Transaction; @@ -41,6 +41,7 @@ OrthancPluginDatabaseBackendV3 backend_; void* database_; std::string serverIdentifier_; + IDatabaseWrapper::Capabilities dbCapabilities_; void CheckSuccess(OrthancPluginErrorCode code) const; @@ -67,11 +68,6 @@ { } - virtual bool HasFlushToDisk() const ORTHANC_OVERRIDE - { - return false; - } - virtual IDatabaseWrapper::ITransaction* StartTransaction(TransactionType type, IDatabaseListener& listener) ORTHANC_OVERRIDE; @@ -81,12 +77,11 @@ virtual void Upgrade(unsigned int targetVersion, IStorageArea& storageArea) ORTHANC_OVERRIDE; - virtual bool HasRevisionsSupport() const ORTHANC_OVERRIDE; + const IDatabaseWrapper::Capabilities& GetDatabaseCapabilities() const ORTHANC_OVERRIDE + { + return dbCapabilities_; + } - virtual bool HasLabelsSupport() const ORTHANC_OVERRIDE - { - return false; - } }; }
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV4.cpp Fri Dec 08 10:26:53 2023 +0100 +++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV4.cpp Fri Dec 08 10:27:24 2023 +0100 @@ -229,7 +229,7 @@ bool isSingleResource, int64_t resource) { - if (database_.HasLabelsSupport()) + if (database_.GetDatabaseCapabilities().HasLabelsSupport()) { DatabasePluginMessages::TransactionRequest request; request.mutable_list_labels()->set_single_resource(isSingleResource); @@ -305,6 +305,10 @@ } } + virtual const IDatabaseWrapper::Capabilities& GetDatabaseCapabilities() const ORTHANC_OVERRIDE + { + return database_.GetDatabaseCapabilities(); + } void* GetTransactionObject() { @@ -772,6 +776,21 @@ } } + + virtual int64_t IncrementGlobalProperty(GlobalProperty property, + int64_t increment, + bool shared) ORTHANC_OVERRIDE + { + DatabasePluginMessages::TransactionRequest request; + request.mutable_increment_global_property()->set_server_id(shared ? "" : database_.GetServerIdentifier()); + request.mutable_increment_global_property()->set_property(property); + request.mutable_increment_global_property()->set_increment(increment); + + DatabasePluginMessages::TransactionResponse response; + ExecuteTransaction(response, DatabasePluginMessages::OPERATION_INCREMENT_GLOBAL_PROPERTY, request); + + return response.increment_global_property().new_value(); + } virtual bool LookupMetadata(std::string& target, int64_t& revision, @@ -948,7 +967,7 @@ LabelsConstraint labelsConstraint, uint32_t limit) ORTHANC_OVERRIDE { - if (!database_.HasLabelsSupport() && + if (!database_.GetDatabaseCapabilities().HasLabelsSupport() && !labels.empty()) { throw OrthancException(ErrorCode_InternalError); @@ -1197,7 +1216,7 @@ virtual void AddLabel(int64_t resource, const std::string& label) ORTHANC_OVERRIDE { - if (database_.HasLabelsSupport()) + if (database_.GetDatabaseCapabilities().HasLabelsSupport()) { DatabasePluginMessages::TransactionRequest request; request.mutable_add_label()->set_id(resource); @@ -1216,7 +1235,7 @@ virtual void RemoveLabel(int64_t resource, const std::string& label) ORTHANC_OVERRIDE { - if (database_.HasLabelsSupport()) + if (database_.GetDatabaseCapabilities().HasLabelsSupport()) { DatabasePluginMessages::TransactionRequest request; request.mutable_remove_label()->set_id(resource); @@ -1256,9 +1275,7 @@ serverIdentifier_(serverIdentifier), open_(false), databaseVersion_(0), - hasFlushToDisk_(false), - hasRevisionsSupport_(false), - hasLabelsSupport_(false) + dbCapabilities_(false, false, false, false) // updated in Open() { CLOG(INFO, PLUGINS) << "Identifier of this Orthanc server for the global properties " << "of the custom database: \"" << serverIdentifier << "\""; @@ -1325,10 +1342,13 @@ DatabasePluginMessages::DatabaseRequest request; DatabasePluginMessages::DatabaseResponse response; ExecuteDatabase(response, *this, DatabasePluginMessages::OPERATION_GET_SYSTEM_INFORMATION, request); - databaseVersion_ = response.get_system_information().database_version(); - hasFlushToDisk_ = response.get_system_information().supports_flush_to_disk(); - hasRevisionsSupport_ = response.get_system_information().supports_revisions(); - hasLabelsSupport_ = response.get_system_information().supports_labels(); + + const ::Orthanc::DatabasePluginMessages::GetSystemInformation_Response& systemInfo = response.get_system_information(); + databaseVersion_ = systemInfo.database_version(); + dbCapabilities_.hasFlushToDisk_ = systemInfo.supports_flush_to_disk(); + dbCapabilities_.hasRevisionsSupport_ = systemInfo.supports_revisions(); + dbCapabilities_.hasLabelsSupport_ = systemInfo.supports_labels(); + dbCapabilities_.hasAtomicIncrementGlobalProperty_ = systemInfo.supports_increment_global_property(); } open_ = true; @@ -1350,23 +1370,11 @@ } - bool OrthancPluginDatabaseV4::HasFlushToDisk() const - { - if (!open_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - return hasFlushToDisk_; - } - } - void OrthancPluginDatabaseV4::FlushToDisk() { if (!open_ || - !hasFlushToDisk_) + !GetDatabaseCapabilities().HasFlushToDisk()) { throw OrthancException(ErrorCode_BadSequenceOfCalls); } @@ -1438,8 +1446,8 @@ } } - - bool OrthancPluginDatabaseV4::HasRevisionsSupport() const + + const IDatabaseWrapper::Capabilities& OrthancPluginDatabaseV4::GetDatabaseCapabilities() const { if (!open_) { @@ -1447,20 +1455,9 @@ } else { - return hasRevisionsSupport_; + return dbCapabilities_; } } - - bool OrthancPluginDatabaseV4::HasLabelsSupport() const - { - if (!open_) - { - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - else - { - return hasLabelsSupport_; - } - } + }
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV4.h Fri Dec 08 10:26:53 2023 +0100 +++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV4.h Fri Dec 08 10:27:24 2023 +0100 @@ -42,9 +42,7 @@ std::string serverIdentifier_; bool open_; unsigned int databaseVersion_; - bool hasFlushToDisk_; - bool hasRevisionsSupport_; - bool hasLabelsSupport_; + IDatabaseWrapper::Capabilities dbCapabilities_; void CheckSuccess(OrthancPluginErrorCode code) const; @@ -82,8 +80,6 @@ virtual void FlushToDisk() ORTHANC_OVERRIDE; - virtual bool HasFlushToDisk() const ORTHANC_OVERRIDE; - virtual IDatabaseWrapper::ITransaction* StartTransaction(TransactionType type, IDatabaseListener& listener) ORTHANC_OVERRIDE; @@ -93,9 +89,7 @@ virtual void Upgrade(unsigned int targetVersion, IStorageArea& storageArea) ORTHANC_OVERRIDE; - virtual bool HasRevisionsSupport() const ORTHANC_OVERRIDE; - - virtual bool HasLabelsSupport() const ORTHANC_OVERRIDE; + virtual const IDatabaseWrapper::Capabilities& GetDatabaseCapabilities() const ORTHANC_OVERRIDE; }; }
--- a/OrthancServer/Plugins/Include/orthanc/OrthancDatabasePlugin.proto Fri Dec 08 10:26:53 2023 +0100 +++ b/OrthancServer/Plugins/Include/orthanc/OrthancDatabasePlugin.proto Fri Dec 08 10:27:24 2023 +0100 @@ -136,6 +136,7 @@ bool supports_flush_to_disk = 2; bool supports_revisions = 3; bool supports_labels = 4; + bool supports_increment_global_property = 5; } } @@ -275,6 +276,7 @@ OPERATION_ADD_LABEL = 45; // New in Orthanc 1.12.0 OPERATION_REMOVE_LABEL = 46; // New in Orthanc 1.12.0 OPERATION_LIST_LABELS = 47; // New in Orthanc 1.12.0 + OPERATION_INCREMENT_GLOBAL_PROPERTY = 48; // New in Orthanc 1.12.X } message Rollback { @@ -628,6 +630,17 @@ } } +message IncrementGlobalProperty { + message Request { + string server_id = 1; + int32 property = 2; + int64 increment = 3; + } + message Response { + int64 new_value = 1; + } +} + message ClearMainDicomTags { message Request { int64 id = 1; @@ -834,6 +847,7 @@ AddLabel.Request add_label = 145; RemoveLabel.Request remove_label = 146; ListLabels.Request list_labels = 147; + IncrementGlobalProperty.Request increment_global_property = 148; } message TransactionResponse { @@ -885,6 +899,7 @@ AddLabel.Response add_label = 145; RemoveLabel.Response remove_label = 146; ListLabels.Response list_labels = 147; + IncrementGlobalProperty.Response increment_global_property = 148; } enum RequestType {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Sources/Database/BaseDatabaseWrapper.h Fri Dec 08 10:27:24 2023 +0100 @@ -0,0 +1,48 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2021-2023 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#pragma once + +#include "IDatabaseWrapper.h" +#include "../../../OrthancFramework/Sources/OrthancException.h" + +namespace Orthanc +{ + /** + * This class provides a default "not implemented" implementation + * for all recent methods (1.12.X) + **/ + class BaseDatabaseWrapper : public IDatabaseWrapper + { + public: + class BaseTransaction : public IDatabaseWrapper::ITransaction + { + virtual int64_t IncrementGlobalProperty(GlobalProperty property, + int64_t increment, + bool shared) ORTHANC_OVERRIDE + { + throw OrthancException(ErrorCode_NotImplemented); // Not supported + } + }; + + }; +} \ No newline at end of file
--- a/OrthancServer/Sources/Database/IDatabaseWrapper.h Fri Dec 08 10:26:53 2023 +0100 +++ b/OrthancServer/Sources/Database/IDatabaseWrapper.h Fri Dec 08 10:27:24 2023 +0100 @@ -39,10 +39,57 @@ class DatabaseConstraint; class ResourcesContent; + class OrthancPluginDatabaseV3; + class OrthancPluginDatabaseV4; class IDatabaseWrapper : public boost::noncopyable { public: + + struct Capabilities + { + friend OrthancPluginDatabaseV3; + friend OrthancPluginDatabaseV4; + + protected: + bool hasFlushToDisk_; + bool hasRevisionsSupport_; + bool hasLabelsSupport_; + bool hasAtomicIncrementGlobalProperty_; + + public: + Capabilities(bool hasFlushToDisk, + bool hasRevisionsSupport, + bool hasLabelsSupport, + bool hasAtomicIncrementGlobalProperty) + : hasFlushToDisk_(hasFlushToDisk), + hasRevisionsSupport_(hasRevisionsSupport), + hasLabelsSupport_(hasLabelsSupport), + hasAtomicIncrementGlobalProperty_(hasAtomicIncrementGlobalProperty) + { + } + + bool HasFlushToDisk() const + { + return hasFlushToDisk_; + } + + bool HasRevisionsSupport() const + { + return hasRevisionsSupport_; + } + + bool HasLabelsSupport() const + { + return hasLabelsSupport_; + } + + bool HasAtomicIncrementGlobalProperty() const + { + return hasAtomicIncrementGlobalProperty_; + } + }; + struct CreateInstanceResult : public boost::noncopyable { bool isNewPatient_; @@ -257,6 +304,12 @@ // List all the labels that are present in any resource virtual void ListAllLabels(std::set<std::string>& target) = 0; + + virtual const IDatabaseWrapper::Capabilities& GetDatabaseCapabilities() const = 0; + + virtual int64_t IncrementGlobalProperty(GlobalProperty property, + int64_t increment, + bool shared) = 0; }; @@ -270,8 +323,6 @@ virtual void FlushToDisk() = 0; - virtual bool HasFlushToDisk() const = 0; - virtual ITransaction* StartTransaction(TransactionType type, IDatabaseListener& listener) = 0; @@ -280,8 +331,6 @@ virtual void Upgrade(unsigned int targetVersion, IStorageArea& storageArea) = 0; - virtual bool HasRevisionsSupport() const = 0; - - virtual bool HasLabelsSupport() const = 0; + virtual const IDatabaseWrapper::Capabilities& GetDatabaseCapabilities() const = 0; }; }
--- a/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp Fri Dec 08 10:26:53 2023 +0100 +++ b/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp Fri Dec 08 10:27:24 2023 +0100 @@ -300,19 +300,27 @@ boost::mutex::scoped_lock lock_; IDatabaseListener& listener_; SignalRemainingAncestor& signalRemainingAncestor_; + const IDatabaseWrapper::Capabilities& dbCapabilities_; public: TransactionBase(boost::mutex& mutex, SQLite::Connection& db, IDatabaseListener& listener, - SignalRemainingAncestor& signalRemainingAncestor) : + SignalRemainingAncestor& signalRemainingAncestor, + const IDatabaseWrapper::Capabilities& dbCapabilities) : UnitTestsTransaction(db), lock_(mutex), listener_(listener), - signalRemainingAncestor_(signalRemainingAncestor) + signalRemainingAncestor_(signalRemainingAncestor), + dbCapabilities_(dbCapabilities) { } + virtual const IDatabaseWrapper::Capabilities& GetDatabaseCapabilities() const ORTHANC_OVERRIDE + { + return dbCapabilities_; + } + IDatabaseListener& GetListener() const { return listener_; @@ -1137,6 +1145,7 @@ target.insert(s.ColumnString(0)); } } + }; @@ -1234,7 +1243,7 @@ public: ReadWriteTransaction(SQLiteDatabaseWrapper& that, IDatabaseListener& listener) : - TransactionBase(that.mutex_, that.db_, listener, *that.signalRemainingAncestor_), + TransactionBase(that.mutex_, that.db_, listener, *that.signalRemainingAncestor_, that.GetDatabaseCapabilities()), that_(that), transaction_(new SQLite::Transaction(that_.db_)) { @@ -1288,7 +1297,7 @@ public: ReadOnlyTransaction(SQLiteDatabaseWrapper& that, IDatabaseListener& listener) : - TransactionBase(that.mutex_, that.db_, listener, *that.signalRemainingAncestor_), + TransactionBase(that.mutex_, that.db_, listener, *that.signalRemainingAncestor_, that.GetDatabaseCapabilities()), that_(that) { if (that_.activeTransaction_ != NULL) @@ -1322,7 +1331,8 @@ SQLiteDatabaseWrapper::SQLiteDatabaseWrapper(const std::string& path) : activeTransaction_(NULL), signalRemainingAncestor_(NULL), - version_(0) + version_(0), + dbCapabilities_(true, false /* TODO: implement revisions in SQLite */, true, false) { db_.Open(path); } @@ -1331,7 +1341,8 @@ SQLiteDatabaseWrapper::SQLiteDatabaseWrapper() : activeTransaction_(NULL), signalRemainingAncestor_(NULL), - version_(0) + version_(0), + dbCapabilities_(true, false /* TODO: implement revisions in SQLite */, true, false) { db_.OpenInMemory(); }
--- a/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.h Fri Dec 08 10:26:53 2023 +0100 +++ b/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.h Fri Dec 08 10:27:24 2023 +0100 @@ -22,7 +22,7 @@ #pragma once -#include "IDatabaseWrapper.h" +#include "BaseDatabaseWrapper.h" #include "../../../OrthancFramework/Sources/SQLite/Connection.h" @@ -35,7 +35,7 @@ * translates low-level requests into SQL statements. Mutual * exclusion MUST be implemented at a higher level. **/ - class SQLiteDatabaseWrapper : public IDatabaseWrapper + class SQLiteDatabaseWrapper : public BaseDatabaseWrapper { private: class TransactionBase; @@ -51,6 +51,7 @@ TransactionBase* activeTransaction_; SignalRemainingAncestor* signalRemainingAncestor_; unsigned int version_; + IDatabaseWrapper::Capabilities dbCapabilities_; void GetChangesInternal(std::list<ServerIndexChange>& target, bool& done, @@ -79,11 +80,6 @@ virtual void FlushToDisk() ORTHANC_OVERRIDE; - virtual bool HasFlushToDisk() const ORTHANC_OVERRIDE - { - return true; - } - virtual unsigned int GetDatabaseVersion() ORTHANC_OVERRIDE { return version_; @@ -92,24 +88,18 @@ virtual void Upgrade(unsigned int targetVersion, IStorageArea& storageArea) ORTHANC_OVERRIDE; - virtual bool HasRevisionsSupport() const ORTHANC_OVERRIDE + virtual const IDatabaseWrapper::Capabilities& GetDatabaseCapabilities() const ORTHANC_OVERRIDE { - return false; // TODO - REVISIONS + return dbCapabilities_; } - virtual bool HasLabelsSupport() const ORTHANC_OVERRIDE - { - return true; - } - - /** * The "StartTransaction()" method is guaranteed to return a class * derived from "UnitTestsTransaction". The methods of * "UnitTestsTransaction" give access to additional information * about the underlying SQLite database to be used in unit tests. **/ - class UnitTestsTransaction : public ITransaction + class UnitTestsTransaction : public BaseDatabaseWrapper::BaseTransaction { protected: SQLite::Connection& db_;
--- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp Fri Dec 08 10:26:53 2023 +0100 +++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp Fri Dec 08 10:27:24 2023 +0100 @@ -607,7 +607,7 @@ Transaction transaction(db_, *factory_, TransactionType_ReadOnly); // TODO - Only if not "TransactionType_Implicit" { - ReadOnlyTransaction t(transaction.GetDatabaseTransaction(), transaction.GetContext(), db_.HasLabelsSupport()); + ReadOnlyTransaction t(transaction.GetDatabaseTransaction(), transaction.GetContext(), db_.GetDatabaseCapabilities()); readOperations->Apply(t); } transaction.Commit(); @@ -618,7 +618,7 @@ Transaction transaction(db_, *factory_, TransactionType_ReadWrite); { - ReadWriteTransaction t(transaction.GetDatabaseTransaction(), transaction.GetContext(), db_.HasLabelsSupport()); + ReadWriteTransaction t(transaction.GetDatabaseTransaction(), transaction.GetContext(), db_.GetDatabaseCapabilities()); writeOperations->Apply(t); } transaction.Commit(); @@ -654,7 +654,6 @@ StatelessDatabaseOperations::StatelessDatabaseOperations(IDatabaseWrapper& db) : db_(db), mainDicomTagsRegistry_(new MainDicomTagsRegistry), - hasFlushToDisk_(db.HasFlushToDisk()), maxRetries_(0) { } @@ -939,7 +938,7 @@ } if ((expandFlags & ExpandResourceFlags_IncludeLabels) && - transaction.HasLabelsSupport()) + transaction.GetDatabaseCapabilities().HasLabelsSupport()) { transaction.ListLabels(target.labels_, internalId); } @@ -1961,7 +1960,7 @@ }; if (!labels.empty() && - !db_.HasLabelsSupport()) + !db_.GetDatabaseCapabilities().HasLabelsSupport()) { throw OrthancException(ErrorCode_NotImplemented, "The database backend doesn't support labels"); } @@ -2431,32 +2430,39 @@ virtual void Apply(ReadWriteTransaction& transaction) ORTHANC_OVERRIDE { - std::string oldString; - - if (transaction.LookupGlobalProperty(oldString, sequence_, shared_)) + if (transaction.GetDatabaseCapabilities().HasAtomicIncrementGlobalProperty()) { - uint64_t oldValue; - - try - { - oldValue = boost::lexical_cast<uint64_t>(oldString); - } - catch (boost::bad_lexical_cast&) - { - LOG(ERROR) << "Cannot read the global sequence " - << boost::lexical_cast<std::string>(sequence_) << ", resetting it"; - oldValue = 0; - } - - newValue_ = oldValue + 1; + newValue_ = static_cast<uint64_t>(transaction.IncrementGlobalProperty(sequence_, shared_, 1)); } else { - // Initialize the sequence at "1" - newValue_ = 1; + std::string oldString; + + if (transaction.LookupGlobalProperty(oldString, sequence_, shared_)) + { + uint64_t oldValue; + + try + { + oldValue = boost::lexical_cast<uint64_t>(oldString); + } + catch (boost::bad_lexical_cast&) + { + LOG(ERROR) << "Cannot read the global sequence " + << boost::lexical_cast<std::string>(sequence_) << ", resetting it"; + oldValue = 0; + } + + newValue_ = oldValue + 1; + } + else + { + // Initialize the sequence at "1" + newValue_ = 1; + } + + transaction.SetGlobalProperty(sequence_, shared_, boost::lexical_cast<std::string>(newValue_)); } - - transaction.SetGlobalProperty(sequence_, shared_, boost::lexical_cast<std::string>(newValue_)); } }; @@ -3147,7 +3153,11 @@ if (!transaction.CreateInstance(status, instanceId, hashPatient_, hashStudy_, hashSeries_, hashInstance_)) { - throw OrthancException(ErrorCode_InternalError, "No new instance while overwriting; this should not happen."); + // Note that, sometime, it does not create a new instance, + // in very rare occasions in READ COMMITTED mode when multiple clients are pushing the same instance at the same time, + // this thread will not create the instance because another thread has created it in the meantime. + // At the end, there is always a thread that creates the instance and this is what we expect. + throw OrthancException(ErrorCode_InternalError, HttpStatus_409_Conflict, "No new instance while overwriting; this might happen if another client has pushed the same instance at the same time."); } } else @@ -3683,6 +3693,6 @@ bool StatelessDatabaseOperations::HasLabelsSupport() { boost::shared_lock<boost::shared_mutex> lock(mutex_); - return db_.HasLabelsSupport(); + return db_.GetDatabaseCapabilities().HasLabelsSupport(); } }
--- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.h Fri Dec 08 10:26:53 2023 +0100 +++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.h Fri Dec 08 10:27:24 2023 +0100 @@ -176,17 +176,17 @@ { private: ITransactionContext& context_; - bool hasLabelsSupport_; - + const IDatabaseWrapper::Capabilities& dbCapabilities_; + protected: IDatabaseWrapper::ITransaction& transaction_; public: explicit ReadOnlyTransaction(IDatabaseWrapper::ITransaction& transaction, ITransactionContext& context, - bool hasLabelsSupport) : + const IDatabaseWrapper::Capabilities& dbCapabilities) : context_(context), - hasLabelsSupport_(hasLabelsSupport), + dbCapabilities_(dbCapabilities), transaction_(transaction) { } @@ -196,9 +196,9 @@ return context_; } - bool HasLabelsSupport() const + const IDatabaseWrapper::Capabilities& GetDatabaseCapabilities() const { - return hasLabelsSupport_; + return dbCapabilities_; } /** @@ -392,8 +392,8 @@ public: ReadWriteTransaction(IDatabaseWrapper::ITransaction& transaction, ITransactionContext& context, - bool hasLabelsSupport) : - ReadOnlyTransaction(transaction, context, hasLabelsSupport) + const IDatabaseWrapper::Capabilities& dbCapabilities) : + ReadOnlyTransaction(transaction, context, dbCapabilities) { } @@ -463,6 +463,13 @@ transaction_.SetGlobalProperty(property, shared, value); } + int64_t IncrementGlobalProperty(GlobalProperty sequence, + bool shared, + int64_t increment) + { + return transaction_.IncrementGlobalProperty(sequence, shared, increment); + } + void SetMetadata(int64_t id, MetadataType type, const std::string& value, @@ -540,7 +547,6 @@ IDatabaseWrapper& db_; boost::shared_ptr<MainDicomTagsRegistry> mainDicomTagsRegistry_; // "shared_ptr" because of PImpl - bool hasFlushToDisk_; // Mutex to protect the configuration options boost::shared_mutex mutex_; @@ -575,12 +581,13 @@ return db_.GetDatabaseVersion(); } + const IDatabaseWrapper::Capabilities& GetDatabaseCapabilities() const + { + return db_.GetDatabaseCapabilities(); + } + void FlushToDisk(); - bool HasFlushToDisk() const - { - return hasFlushToDisk_; - } void Apply(IReadOnlyOperations& operations);
--- a/OrthancServer/Sources/ServerIndex.cpp Fri Dec 08 10:26:53 2023 +0100 +++ b/OrthancServer/Sources/ServerIndex.cpp Fri Dec 08 10:27:24 2023 +0100 @@ -331,7 +331,7 @@ // execution of Orthanc StandaloneRecycling(maximumStorageMode_, maximumStorageSize_, maximumPatients_); - if (HasFlushToDisk()) + if (GetDatabaseCapabilities().HasFlushToDisk()) { flushThread_ = boost::thread(FlushThread, this, threadSleepGranularityMilliseconds); }
--- a/OrthancServer/Sources/main.cpp Fri Dec 08 10:26:53 2023 +0100 +++ b/OrthancServer/Sources/main.cpp Fri Dec 08 10:27:24 2023 +0100 @@ -1643,7 +1643,7 @@ if (lock.GetConfiguration().GetBooleanParameter(CHECK_REVISIONS, false)) { - if (database.HasRevisionsSupport()) + if (database.GetDatabaseCapabilities().HasRevisionsSupport()) { LOG(INFO) << "Handling of revisions is enabled, and the custom database back-end *has* " << "support for revisions of metadata and attachments"; @@ -1666,7 +1666,7 @@ } } - if (!database.HasLabelsSupport()) + if (!database.GetDatabaseCapabilities().HasLabelsSupport()) { LOG(WARNING) << "The custom database back-end has *no* support for labels"; }