changeset 5466:dceed5e3d6a9 pg-transactions

new DB plugin primitive: UpdateAndGetStatistics
author Alain Mazy <am@osimis.io>
date Fri, 15 Dec 2023 17:15:43 +0100
parents 2829889bfa57
children 4b51cf06b697
files OrthancServer/Plugins/Engine/OrthancPluginDatabase.cpp OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.cpp OrthancServer/Plugins/Engine/OrthancPluginDatabaseV4.cpp OrthancServer/Plugins/Include/orthanc/OrthancDatabasePlugin.proto OrthancServer/Sources/Database/BaseDatabaseWrapper.h OrthancServer/Sources/Database/IDatabaseWrapper.h OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp OrthancServer/Sources/Database/StatelessDatabaseOperations.h
diffstat 9 files changed, 155 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabase.cpp	Wed Dec 13 15:44:33 2023 +0100
+++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabase.cpp	Fri Dec 15 17:15:43 2023 +0100
@@ -1478,7 +1478,7 @@
     activeTransaction_(NULL),
     fastGetTotalSize_(false),
     currentDiskSize_(0),
-    dbCapabilities_(false, false, false, false)
+    dbCapabilities_(false, false, false, false, false)
   {
     static const char* const MISSING = "  Missing extension in database index plugin: ";
     
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.cpp	Wed Dec 13 15:44:33 2023 +0100
+++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV3.cpp	Fri Dec 15 17:15:43 2023 +0100
@@ -1088,7 +1088,11 @@
     errorDictionary_(errorDictionary),
     database_(database),
     serverIdentifier_(serverIdentifier),
-    dbCapabilities_(false, false /* revision support is updated in open() */, false, false)
+    dbCapabilities_(false,  /* hasFlushToDisk */
+                    false,  /* revision support is updated in open() */ 
+                    false,  /* hasLabelsSupport */
+                    false,  /* hasAtomicIncrementGlobalProperty */
+                    false   /* hasUpdateAndGetStatistics */)
   {
     CLOG(INFO, PLUGINS) << "Identifier of this Orthanc server for the global properties "
                         << "of the custom database: \"" << serverIdentifier << "\"";
--- a/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV4.cpp	Wed Dec 13 15:44:33 2023 +0100
+++ b/OrthancServer/Plugins/Engine/OrthancPluginDatabaseV4.cpp	Fri Dec 15 17:15:43 2023 +0100
@@ -791,7 +791,25 @@
 
       return response.increment_global_property().new_value();
     }
-    
+
+    virtual void UpdateAndGetStatistics(int64_t& patientsCount,
+                                        int64_t& studiesCount,
+                                        int64_t& seriesCount,
+                                        int64_t& instancesCount,
+                                        int64_t& compressedSize,
+                                        int64_t& uncompressedSize) ORTHANC_OVERRIDE
+    {
+      DatabasePluginMessages::TransactionResponse response;
+      ExecuteTransaction(response, DatabasePluginMessages::OPERATION_UPDATE_AND_GET_STATISTICS);
+
+      patientsCount = response.update_and_get_statistics().patients_count();
+      studiesCount = response.update_and_get_statistics().studies_count();
+      seriesCount = response.update_and_get_statistics().series_count();
+      instancesCount = response.update_and_get_statistics().instances_count();
+      compressedSize = response.update_and_get_statistics().total_compressed_size();
+      uncompressedSize = response.update_and_get_statistics().total_uncompressed_size();
+    }
+
     virtual bool LookupMetadata(std::string& target,
                                 int64_t& revision,
                                 int64_t id,
@@ -1275,7 +1293,7 @@
     serverIdentifier_(serverIdentifier),
     open_(false),
     databaseVersion_(0),
-    dbCapabilities_(false, false, false, false) // updated in Open()
+    dbCapabilities_(false, false, false, false, false) // updated in Open()
   {
     CLOG(INFO, PLUGINS) << "Identifier of this Orthanc server for the global properties "
                         << "of the custom database: \"" << serverIdentifier << "\"";
@@ -1349,6 +1367,7 @@
       dbCapabilities_.hasRevisionsSupport_ = systemInfo.supports_revisions();
       dbCapabilities_.hasLabelsSupport_ = systemInfo.supports_labels();
       dbCapabilities_.hasAtomicIncrementGlobalProperty_ = systemInfo.supports_increment_global_property();
+      dbCapabilities_.hasUpdateAndGetStatistics_ = systemInfo.has_update_and_get_statistics();
     }
 
     open_ = true;
--- a/OrthancServer/Plugins/Include/orthanc/OrthancDatabasePlugin.proto	Wed Dec 13 15:44:33 2023 +0100
+++ b/OrthancServer/Plugins/Include/orthanc/OrthancDatabasePlugin.proto	Fri Dec 15 17:15:43 2023 +0100
@@ -137,6 +137,7 @@
     bool supports_revisions = 3;
     bool supports_labels = 4;
     bool supports_increment_global_property = 5;
+    bool has_update_and_get_statistics = 6;
   }
 }
 
@@ -277,6 +278,7 @@
   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
+  OPERATION_UPDATE_AND_GET_STATISTICS = 49;      // New in Orthanc 1.12.X
 }
 
 message Rollback {
@@ -641,6 +643,19 @@
   }
 }
 
+message UpdateAndGetStatistics {
+  message Request {
+  }
+  message Response {
+    int64 patients_count = 1;
+    int64 studies_count = 2;
+    int64 series_count = 3;
+    int64 instances_count = 4;
+    int64 total_compressed_size = 5;
+    int64 total_uncompressed_size = 6;
+  }
+}
+
 message ClearMainDicomTags {
   message Request {
     int64 id = 1;
@@ -848,6 +863,7 @@
   RemoveLabel.Request                     remove_label = 146;
   ListLabels.Request                      list_labels = 147;
   IncrementGlobalProperty.Request         increment_global_property = 148;
+  UpdateAndGetStatistics.Request          update_and_get_statistics = 149;
 }
 
 message TransactionResponse {
@@ -900,6 +916,7 @@
   RemoveLabel.Response                     remove_label = 146;
   ListLabels.Response                      list_labels = 147;
   IncrementGlobalProperty.Response         increment_global_property = 148;
+  UpdateAndGetStatistics.Response          update_and_get_statistics = 149;
 }
 
 enum RequestType {
--- a/OrthancServer/Sources/Database/BaseDatabaseWrapper.h	Wed Dec 13 15:44:33 2023 +0100
+++ b/OrthancServer/Sources/Database/BaseDatabaseWrapper.h	Fri Dec 15 17:15:43 2023 +0100
@@ -42,6 +42,17 @@
       {
         throw OrthancException(ErrorCode_NotImplemented);  // Not supported
       }
+
+      virtual void UpdateAndGetStatistics(int64_t& patientsCount,
+                                          int64_t& studiesCount,
+                                          int64_t& seriesCount,
+                                          int64_t& instancesCount,
+                                          int64_t& compressedSize,
+                                          int64_t& uncompressedSize) ORTHANC_OVERRIDE
+      {
+        throw OrthancException(ErrorCode_NotImplemented);  // Not supported
+      }
+
     };
 
   };
--- a/OrthancServer/Sources/Database/IDatabaseWrapper.h	Wed Dec 13 15:44:33 2023 +0100
+++ b/OrthancServer/Sources/Database/IDatabaseWrapper.h	Fri Dec 15 17:15:43 2023 +0100
@@ -56,16 +56,19 @@
       bool hasRevisionsSupport_;
       bool hasLabelsSupport_;
       bool hasAtomicIncrementGlobalProperty_;
+      bool hasUpdateAndGetStatistics_;
 
     public:
       Capabilities(bool hasFlushToDisk,
                    bool hasRevisionsSupport,
                    bool hasLabelsSupport,
-                   bool hasAtomicIncrementGlobalProperty)
+                   bool hasAtomicIncrementGlobalProperty,
+                   bool hasUpdateAndGetStatistics)
       : hasFlushToDisk_(hasFlushToDisk),
         hasRevisionsSupport_(hasRevisionsSupport),
         hasLabelsSupport_(hasLabelsSupport),
-        hasAtomicIncrementGlobalProperty_(hasAtomicIncrementGlobalProperty)
+        hasAtomicIncrementGlobalProperty_(hasAtomicIncrementGlobalProperty),
+        hasUpdateAndGetStatistics_(hasUpdateAndGetStatistics)
       {
       }
 
@@ -88,6 +91,12 @@
       {
         return hasAtomicIncrementGlobalProperty_;
       }
+
+      bool HasUpdateAndGetStatistics() const
+      {
+        return hasUpdateAndGetStatistics_;
+      }
+
     };
 
     struct CreateInstanceResult : public boost::noncopyable
@@ -310,6 +319,13 @@
       virtual int64_t IncrementGlobalProperty(GlobalProperty property,
                                               int64_t increment,
                                               bool shared) = 0;
+
+      virtual void UpdateAndGetStatistics(int64_t& patientsCount,
+                                          int64_t& studiesCount,
+                                          int64_t& seriesCount,
+                                          int64_t& instancesCount,
+                                          int64_t& compressedSize,
+                                          int64_t& uncompressedSize) = 0;
     };
 
 
--- a/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp	Wed Dec 13 15:44:33 2023 +0100
+++ b/OrthancServer/Sources/Database/SQLiteDatabaseWrapper.cpp	Fri Dec 15 17:15:43 2023 +0100
@@ -1332,7 +1332,11 @@
     activeTransaction_(NULL), 
     signalRemainingAncestor_(NULL),
     version_(0),
-    dbCapabilities_(true, false /* TODO: implement revisions in SQLite */, true, false)
+    dbCapabilities_(true,  /* hasFlushToDisk */
+                    false, /* hasRevisionsSupport TODO: implement revisions in SQLite */ 
+                    true,  /* hasLabelsSupport */
+                    false, /* hasAtomicIncrementGlobalProperty */
+                    false  /* hasUpdateAndGetStatistics */)
   {
     db_.Open(path);
   }
@@ -1342,7 +1346,11 @@
     activeTransaction_(NULL), 
     signalRemainingAncestor_(NULL),
     version_(0),
-    dbCapabilities_(true, false /* TODO: implement revisions in SQLite */, true, false)
+    dbCapabilities_(true,  /* hasFlushToDisk */
+                    false, /* hasRevisionsSupport TODO: implement revisions in SQLite */ 
+                    true,  /* hasLabelsSupport */
+                    false, /* hasAtomicIncrementGlobalProperty */
+                    false  /* hasUpdateAndGetStatistics */)
   {
     db_.OpenInMemory();
   }
--- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp	Wed Dec 13 15:44:33 2023 +0100
+++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp	Fri Dec 15 17:15:43 2023 +0100
@@ -1102,7 +1102,54 @@
                                                         /* out */ uint64_t& countSeries, 
                                                         /* out */ uint64_t& countInstances)
   {
-    class Operations : public ReadOnlyOperationsT6<uint64_t&, uint64_t&, uint64_t&, uint64_t&, uint64_t&, uint64_t&>
+    // new code that updates and gets all statistics.
+    // I.e, PostgreSQL now store "changes" to apply to the statistics to prevent row locking
+    // of the GlobalIntegers table while multiple clients are inserting/deleting new resources.
+    // Then, the statistics are updated when requested to make sure they are correct.
+    class Operations : public IReadWriteOperations
+    {
+    private:
+      int64_t diskSize_;
+      int64_t uncompressedSize_;
+      int64_t countPatients_;
+      int64_t countStudies_;
+      int64_t countSeries_;
+      int64_t countInstances_;
+
+    public:
+      Operations() :
+        diskSize_(0),
+        uncompressedSize_(0),
+        countPatients_(0),
+        countStudies_(0),
+        countSeries_(0),
+        countInstances_(0)
+      {
+      }
+
+      void GetValues(uint64_t& diskSize,
+                     uint64_t& uncompressedSize,
+                     uint64_t& countPatients, 
+                     uint64_t& countStudies, 
+                     uint64_t& countSeries, 
+                     uint64_t& countInstances) const
+      {
+        diskSize = static_cast<uint64_t>(diskSize_);
+        uncompressedSize = static_cast<uint64_t>(uncompressedSize_);
+        countPatients = static_cast<uint64_t>(countPatients_);
+        countStudies = static_cast<uint64_t>(countStudies_);
+        countSeries = static_cast<uint64_t>(countSeries_);
+        countInstances = static_cast<uint64_t>(countInstances_);
+      }
+
+      virtual void Apply(ReadWriteTransaction& transaction) ORTHANC_OVERRIDE
+      {
+        transaction.UpdateAndGetStatistics(countPatients_, countStudies_, countSeries_, countInstances_, diskSize_, uncompressedSize_);
+      }
+    };
+
+    // legacy oprations that reads each entry individualy
+    class LegacyOperations : public ReadOnlyOperationsT6<uint64_t&, uint64_t&, uint64_t&, uint64_t&, uint64_t&, uint64_t&>
     {
     public:
       virtual void ApplyTuple(ReadOnlyTransaction& transaction,
@@ -1116,10 +1163,20 @@
         tuple.get<5>() = transaction.GetResourcesCount(ResourceType_Instance);
       }
     };
-    
-    Operations operations;
-    operations.Apply(*this, diskSize, uncompressedSize, countPatients,
-                     countStudies, countSeries, countInstances);
+
+    if (GetDatabaseCapabilities().HasUpdateAndGetStatistics())
+    {
+      Operations operations;
+      Apply(operations);
+
+      operations.GetValues(diskSize, uncompressedSize, countPatients, countStudies, countSeries, countInstances);
+    } 
+    else
+    {   
+      LegacyOperations operations;
+      operations.Apply(*this, diskSize, uncompressedSize, countPatients,
+                       countStudies, countSeries, countInstances);
+    }
   }
 
 
--- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.h	Wed Dec 13 15:44:33 2023 +0100
+++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.h	Fri Dec 15 17:15:43 2023 +0100
@@ -470,6 +470,16 @@
         return transaction_.IncrementGlobalProperty(sequence, shared, increment);
       }
 
+      void UpdateAndGetStatistics(int64_t& patientsCount,
+                                  int64_t& studiesCount,
+                                  int64_t& seriesCount,
+                                  int64_t& instancesCount,
+                                  int64_t& compressedSize,
+                                  int64_t& uncompressedSize)
+      {
+        return transaction_.UpdateAndGetStatistics(patientsCount, studiesCount, seriesCount, instancesCount, compressedSize, uncompressedSize);
+      }
+
       void SetMetadata(int64_t id,
                        MetadataType type,
                        const std::string& value,