Mercurial > hg > orthanc
diff OrthancServer/Sources/Database/StatelessDatabaseOperations.h @ 4586:1d96fe7e054e db-changes
taking StatelessDatabaseOperations out of ServerIndex
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 09 Mar 2021 18:24:59 +0100 |
parents | |
children | 888868a5dc4e |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.h Tue Mar 09 18:24:59 2021 +0100 @@ -0,0 +1,595 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2021 Osimis S.A., 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. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * 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 "../../../OrthancFramework/Sources/DicomFormat/DicomMap.h" + +#include "IDatabaseWrapper.h" +#include "../DicomInstanceOrigin.h" + +#include <boost/thread/mutex.hpp> // TODO - REMOVE + + +namespace Orthanc +{ + class DatabaseLookup; + class ParsedDicomFile; + class ServerIndexChange; + + class StatelessDatabaseOperations : public boost::noncopyable + { + public: + typedef std::list<FileInfo> Attachments; + typedef std::map<std::pair<ResourceType, MetadataType>, std::string> MetadataMap; + + class ITransactionContext : public boost::noncopyable + { + public: + virtual ~ITransactionContext() + { + } + + virtual void Commit() = 0; + + virtual int64_t GetCompressedSizeDelta() = 0; + + virtual bool IsUnstableResource(int64_t id) = 0; + + virtual bool LookupRemainingLevel(std::string& remainingPublicId /* out */, + ResourceType& remainingLevel /* out */) = 0; + + virtual void MarkAsUnstable(int64_t id, + Orthanc::ResourceType type, + const std::string& publicId) = 0; + + virtual void SignalAttachmentsAdded(uint64_t compressedSize) = 0; + + virtual void SignalChange(const ServerIndexChange& change) = 0; + }; + + + class ITransactionContextFactory : public boost::noncopyable + { + public: + virtual ~ITransactionContextFactory() + { + } + + virtual ITransactionContext* Create() = 0; + }; + + + class ReadOnlyTransaction : public boost::noncopyable + { + private: + ITransactionContext& context_; + + protected: + IDatabaseWrapper& db_; + + public: + explicit ReadOnlyTransaction(IDatabaseWrapper& db, + ITransactionContext& context) : + context_(context), + db_(db) + { + } + + ITransactionContext& GetTransactionContext() + { + return context_; + } + + /** + * Higher-level constructions + **/ + + SeriesStatus GetSeriesStatus(int64_t id, + int64_t expectedNumberOfInstances); + + + /** + * Read-only methods from "IDatabaseWrapper" + **/ + + void ApplyLookupResources(std::list<std::string>& resourcesId, + std::list<std::string>* instancesId, // Can be NULL if not needed + const std::vector<DatabaseConstraint>& lookup, + ResourceType queryLevel, + size_t limit) + { + return db_.ApplyLookupResources(resourcesId, instancesId, lookup, queryLevel, limit); + } + + void GetAllMetadata(std::map<MetadataType, std::string>& target, + int64_t id) + { + db_.GetAllMetadata(target, id); + } + + void GetAllPublicIds(std::list<std::string>& target, + ResourceType resourceType) + { + return db_.GetAllPublicIds(target, resourceType); + } + + void GetAllPublicIds(std::list<std::string>& target, + ResourceType resourceType, + size_t since, + size_t limit) + { + return db_.GetAllPublicIds(target, resourceType, since, limit); + } + + void GetChanges(std::list<ServerIndexChange>& target /*out*/, + bool& done /*out*/, + int64_t since, + uint32_t maxResults) + { + db_.GetChanges(target, done, since, maxResults); + } + + void GetChildrenInternalId(std::list<int64_t>& target, + int64_t id) + { + db_.GetChildrenInternalId(target, id); + } + + void GetChildrenPublicId(std::list<std::string>& target, + int64_t id) + { + db_.GetChildrenPublicId(target, id); + } + + void GetExportedResources(std::list<ExportedResource>& target /*out*/, + bool& done /*out*/, + int64_t since, + uint32_t maxResults) + { + return db_.GetExportedResources(target, done, since, maxResults); + } + + void GetLastChange(std::list<ServerIndexChange>& target /*out*/) + { + db_.GetLastChange(target); + } + + void GetLastExportedResource(std::list<ExportedResource>& target /*out*/) + { + return db_.GetLastExportedResource(target); + } + + int64_t GetLastChangeIndex() + { + return db_.GetLastChangeIndex(); + } + + void GetMainDicomTags(DicomMap& map, + int64_t id) + { + db_.GetMainDicomTags(map, id); + } + + std::string GetPublicId(int64_t resourceId) + { + return db_.GetPublicId(resourceId); + } + + uint64_t GetResourceCount(ResourceType resourceType) + { + return db_.GetResourceCount(resourceType); + } + + ResourceType GetResourceType(int64_t resourceId) + { + return db_.GetResourceType(resourceId); + } + + uint64_t GetTotalCompressedSize() + { + return db_.GetTotalCompressedSize(); + } + + uint64_t GetTotalUncompressedSize() + { + return db_.GetTotalUncompressedSize(); + } + + bool IsProtectedPatient(int64_t internalId) + { + return db_.IsProtectedPatient(internalId); + } + + void ListAvailableAttachments(std::set<FileContentType>& target, + int64_t id) + { + db_.ListAvailableAttachments(target, id); + } + + bool LookupAttachment(FileInfo& attachment, + int64_t id, + FileContentType contentType) + { + return db_.LookupAttachment(attachment, id, contentType); + } + + bool LookupGlobalProperty(std::string& target, + GlobalProperty property) + { + return db_.LookupGlobalProperty(target, property); + } + + bool LookupMetadata(std::string& target, + int64_t id, + MetadataType type) + { + return db_.LookupMetadata(target, id, type); + } + + bool LookupParent(int64_t& parentId, + int64_t resourceId) + { + return db_.LookupParent(parentId, resourceId); + } + + bool LookupResource(int64_t& id, + ResourceType& type, + const std::string& publicId) + { + return db_.LookupResource(id, type, publicId); + } + + bool LookupResourceAndParent(int64_t& id, + ResourceType& type, + std::string& parentPublicId, + const std::string& publicId) + { + return db_.LookupResourceAndParent(id, type, parentPublicId, publicId); + } + }; + + + class ReadWriteTransaction : public ReadOnlyTransaction + { + public: + ReadWriteTransaction(IDatabaseWrapper& db, + ITransactionContext& context) : + ReadOnlyTransaction(db, context) + { + } + + void AddAttachment(int64_t id, + const FileInfo& attachment) + { + db_.AddAttachment(id, attachment); + } + + void ClearChanges() + { + db_.ClearChanges(); + } + + void ClearExportedResources() + { + db_.ClearExportedResources(); + } + + void ClearMainDicomTags(int64_t id) + { + return db_.ClearMainDicomTags(id); + } + + bool CreateInstance(IDatabaseWrapper::CreateInstanceResult& result, /* out */ + int64_t& instanceId, /* out */ + const std::string& patient, + const std::string& study, + const std::string& series, + const std::string& instance) + { + return db_.CreateInstance(result, instanceId, patient, study, series, instance); + } + + void DeleteAttachment(int64_t id, + FileContentType attachment) + { + return db_.DeleteAttachment(id, attachment); + } + + void DeleteMetadata(int64_t id, + MetadataType type) + { + db_.DeleteMetadata(id, type); + } + + void DeleteResource(int64_t id) + { + db_.DeleteResource(id); + } + + void LogChange(int64_t internalId, + ChangeType changeType, + ResourceType resourceType, + const std::string& publicId); + + void LogExportedResource(const ExportedResource& resource) + { + db_.LogExportedResource(resource); + } + + void SetGlobalProperty(GlobalProperty property, + const std::string& value) + { + db_.SetGlobalProperty(property, value); + } + + void SetMetadata(int64_t id, + MetadataType type, + const std::string& value) + { + return db_.SetMetadata(id, type, value); + } + + void SetProtectedPatient(int64_t internalId, + bool isProtected) + { + db_.SetProtectedPatient(internalId, isProtected); + } + + void SetResourcesContent(const ResourcesContent& content) + { + db_.SetResourcesContent(content); + } + + void Recycle(uint64_t maximumStorageSize, + unsigned int maximumPatients, + uint64_t addedInstanceSize, + const std::string& newPatientId); + }; + + + class IReadOnlyOperations : public boost::noncopyable + { + public: + virtual ~IReadOnlyOperations() + { + } + + virtual void Apply(ReadOnlyTransaction& transaction) = 0; + }; + + + class IReadWriteOperations : public boost::noncopyable + { + public: + virtual ~IReadWriteOperations() + { + } + + virtual void Apply(ReadWriteTransaction& transaction) = 0; + }; + + + private: + class MainDicomTagsRegistry; + class Transaction; + + IDatabaseWrapper& db_; + boost::mutex databaseMutex_; // TODO - REMOVE + std::unique_ptr<ITransactionContextFactory> factory_; + unsigned int maxRetries_; + std::unique_ptr<MainDicomTagsRegistry> mainDicomTagsRegistry_; + + void NormalizeLookup(std::vector<DatabaseConstraint>& target, + const DatabaseLookup& source, + ResourceType level) const; + + void ApplyInternal(IReadOnlyOperations* readOperations, + IReadWriteOperations* writeOperations); + + protected: + void StandaloneRecycling(uint64_t maximumStorageSize, + unsigned int maximumPatientCount); + + public: + StatelessDatabaseOperations(IDatabaseWrapper& database); + + void SetTransactionContextFactory(ITransactionContextFactory* factory /* takes ownership */); + + // It is assumed that "GetDatabaseVersion()" can run out of a + // database transaction + unsigned int GetDatabaseVersion() + { + return db_.GetDatabaseVersion(); + } + + void Apply(IReadOnlyOperations& operations); + + void Apply(IReadWriteOperations& operations); + + bool ExpandResource(Json::Value& target, + const std::string& publicId, + ResourceType level); + + void GetAllMetadata(std::map<MetadataType, std::string>& target, + const std::string& publicId, + ResourceType level); + + void GetAllUuids(std::list<std::string>& target, + ResourceType resourceType); + + void GetAllUuids(std::list<std::string>& target, + ResourceType resourceType, + size_t since, + size_t limit); + + void GetGlobalStatistics(/* out */ uint64_t& diskSize, + /* out */ uint64_t& uncompressedSize, + /* out */ uint64_t& countPatients, + /* out */ uint64_t& countStudies, + /* out */ uint64_t& countSeries, + /* out */ uint64_t& countInstances); + + bool LookupAttachment(FileInfo& attachment, + const std::string& instancePublicId, + FileContentType contentType); + + void GetChanges(Json::Value& target, + int64_t since, + unsigned int maxResults); + + void GetLastChange(Json::Value& target); + + void GetExportedResources(Json::Value& target, + int64_t since, + unsigned int maxResults); + + void GetLastExportedResource(Json::Value& target); + + bool IsProtectedPatient(const std::string& publicId); + + void GetChildren(std::list<std::string>& result, + const std::string& publicId); + + void GetChildInstances(std::list<std::string>& result, + const std::string& publicId); + + bool LookupMetadata(std::string& target, + const std::string& publicId, + ResourceType expectedType, + MetadataType type); + + void ListAvailableAttachments(std::set<FileContentType>& target, + const std::string& publicId, + ResourceType expectedType); + + bool LookupParent(std::string& target, + const std::string& publicId); + + void GetResourceStatistics(/* out */ ResourceType& type, + /* out */ uint64_t& diskSize, + /* out */ uint64_t& uncompressedSize, + /* out */ unsigned int& countStudies, + /* out */ unsigned int& countSeries, + /* out */ unsigned int& countInstances, + /* out */ uint64_t& dicomDiskSize, + /* out */ uint64_t& dicomUncompressedSize, + const std::string& publicId); + + void LookupIdentifierExact(std::vector<std::string>& result, + ResourceType level, + const DicomTag& tag, + const std::string& value); + + bool LookupGlobalProperty(std::string& value, + GlobalProperty property); + + std::string GetGlobalProperty(GlobalProperty property, + const std::string& defaultValue); + + bool GetMainDicomTags(DicomMap& result, + const std::string& publicId, + ResourceType expectedType, + ResourceType levelOfInterest); + + // Only applicable at the instance level + bool GetAllMainDicomTags(DicomMap& result, + const std::string& instancePublicId); + + bool LookupResourceType(ResourceType& type, + const std::string& publicId); + + bool LookupParent(std::string& target, + const std::string& publicId, + ResourceType parentType); + + void ApplyLookupResources(std::vector<std::string>& resourcesId, + std::vector<std::string>* instancesId, // Can be NULL if not needed + const DatabaseLookup& lookup, + ResourceType queryLevel, + size_t limit); + + bool DeleteResource(Json::Value& target /* out */, + const std::string& uuid, + ResourceType expectedType); + + void LogExportedResource(const std::string& publicId, + const std::string& remoteModality); + + void SetProtectedPatient(const std::string& publicId, + bool isProtected); + + void SetMetadata(const std::string& publicId, + MetadataType type, + const std::string& value); + + void DeleteMetadata(const std::string& publicId, + MetadataType type); + + uint64_t IncrementGlobalSequence(GlobalProperty sequence); + + void DeleteChanges(); + + void DeleteExportedResources(); + + void SetGlobalProperty(GlobalProperty property, + const std::string& value); + + void DeleteAttachment(const std::string& publicId, + FileContentType type); + + void LogChange(ChangeType changeType, + const std::string& publicId, + ResourceType level); + + void ReconstructInstance(const ParsedDicomFile& dicom); + + StoreStatus Store(std::map<MetadataType, std::string>& instanceMetadata, + const DicomMap& dicomSummary, + const Attachments& attachments, + const MetadataMap& metadata, + const DicomInstanceOrigin& origin, + bool overwrite, + bool hasTransferSyntax, + DicomTransferSyntax transferSyntax, + bool hasPixelDataOffset, + uint64_t pixelDataOffset, + uint64_t maximumStorageSize, + unsigned int maximumPatients); + + StoreStatus AddAttachment(const FileInfo& attachment, + const std::string& publicId, + uint64_t maximumStorageSize, + unsigned int maximumPatients); + }; +}