diff OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp @ 5061:e95fadefeb72

new MaximumStorageMode configuration
author Alain Mazy <am@osimis.io>
date Tue, 09 Aug 2022 17:57:38 +0200
parents 6fed78e13233
children 48005e522bd6
line wrap: on
line diff
--- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp	Mon Aug 08 12:42:48 2022 +0200
+++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp	Tue Aug 09 17:57:38 2022 +0200
@@ -2773,10 +2773,8 @@
   }
 
 
-  static bool IsRecyclingNeeded(IDatabaseWrapper::ITransaction& transaction,
-                                uint64_t maximumStorageSize,
-                                unsigned int maximumPatients,
-                                uint64_t addedInstanceSize)
+  bool StatelessDatabaseOperations::ReadWriteTransaction::HasReachedMaxStorageSize(uint64_t maximumStorageSize,
+                                                                                   uint64_t addedInstanceSize)
   {
     if (maximumStorageSize != 0)
     {
@@ -2788,24 +2786,35 @@
                                boost::lexical_cast<std::string>(maximumStorageSize));
       }
       
-      if (transaction.IsDiskSizeAbove(maximumStorageSize - addedInstanceSize))
-      {
-        return true;
-      }
-    }
-
-    if (maximumPatients != 0)
-    {
-      uint64_t patientCount = transaction.GetResourcesCount(ResourceType_Patient);
-      if (patientCount > maximumPatients)
+      if (transaction_.IsDiskSizeAbove(maximumStorageSize - addedInstanceSize))
       {
         return true;
       }
     }
 
     return false;
+  }                                                                           
+
+  bool StatelessDatabaseOperations::ReadWriteTransaction::HasReachedMaxPatientCount(unsigned int maximumPatientCount,
+                                                                                   const std::string& patientId)
+  {
+    if (maximumPatientCount != 0)
+    {
+      uint64_t patientCount = transaction_.GetResourcesCount(ResourceType_Patient);  // at this time, the new patient has already been added (as part of the transaction)
+      return patientCount > maximumPatientCount;
+    }
+
+    return false;
   }
   
+  bool StatelessDatabaseOperations::ReadWriteTransaction::IsRecyclingNeeded(uint64_t maximumStorageSize,
+                                                                            unsigned int maximumPatients,
+                                                                            uint64_t addedInstanceSize,
+                                                                            const std::string& newPatientId)
+  {
+    return HasReachedMaxStorageSize(maximumStorageSize, addedInstanceSize)
+      || HasReachedMaxPatientCount(maximumPatients, newPatientId);
+  }
 
   void StatelessDatabaseOperations::ReadWriteTransaction::Recycle(uint64_t maximumStorageSize,
                                                                   unsigned int maximumPatients,
@@ -2814,7 +2823,7 @@
   {
     // TODO - Performance: Avoid calls to "IsRecyclingNeeded()"
     
-    if (IsRecyclingNeeded(transaction_, maximumStorageSize, maximumPatients, addedInstanceSize))
+    if (IsRecyclingNeeded(maximumStorageSize, maximumPatients, addedInstanceSize, newPatientId))
     {
       // Check whether other DICOM instances from this patient are
       // already stored
@@ -2854,7 +2863,7 @@
         LOG(TRACE) << "Recycling one patient";
         transaction_.DeleteResource(patientToRecycle);
 
-        if (!IsRecyclingNeeded(transaction_, maximumStorageSize, maximumPatients, addedInstanceSize))
+        if (!IsRecyclingNeeded(maximumStorageSize, maximumPatients, addedInstanceSize, newPatientId))
         {
           // OK, we're done
           return;
@@ -2864,14 +2873,15 @@
   }
 
 
-  void StatelessDatabaseOperations::StandaloneRecycling(uint64_t maximumStorageSize,
+  void StatelessDatabaseOperations::StandaloneRecycling(MaxStorageMode maximumStorageMode,
+                                                        uint64_t maximumStorageSize,
                                                         unsigned int maximumPatientCount)
   {
     class Operations : public IReadWriteOperations
     {
     private:
-      uint64_t      maximumStorageSize_;
-      unsigned int  maximumPatientCount_;
+      uint64_t        maximumStorageSize_;
+      unsigned int    maximumPatientCount_;
       
     public:
       Operations(uint64_t maximumStorageSize,
@@ -2887,8 +2897,8 @@
       }
     };
 
-    if (maximumStorageSize != 0 ||
-        maximumPatientCount != 0)
+    if (maximumStorageMode == MaxStorageMode_Recycle 
+      && (maximumStorageSize != 0 || maximumPatientCount != 0))
     {
       Operations operations(maximumStorageSize, maximumPatientCount);
       Apply(operations);
@@ -2906,6 +2916,7 @@
                                                  DicomTransferSyntax transferSyntax,
                                                  bool hasPixelDataOffset,
                                                  uint64_t pixelDataOffset,
+                                                 MaxStorageMode maximumStorageMode,
                                                  uint64_t maximumStorageSize,
                                                  unsigned int maximumPatients,
                                                  bool isReconstruct)
@@ -2924,6 +2935,7 @@
       DicomTransferSyntax                  transferSyntax_;
       bool                                 hasPixelDataOffset_;
       uint64_t                             pixelDataOffset_;
+      MaxStorageMode                       maximumStorageMode_;
       uint64_t                             maximumStorageSize_;
       unsigned int                         maximumPatientCount_;
       bool                                 isReconstruct_;
@@ -3026,6 +3038,7 @@
                  DicomTransferSyntax transferSyntax,
                  bool hasPixelDataOffset,
                  uint64_t pixelDataOffset,
+                 MaxStorageMode maximumStorageMode,
                  uint64_t maximumStorageSize,
                  unsigned int maximumPatientCount,
                  bool isReconstruct) :
@@ -3040,6 +3053,7 @@
         transferSyntax_(transferSyntax),
         hasPixelDataOffset_(hasPixelDataOffset),
         pixelDataOffset_(pixelDataOffset),
+        maximumStorageMode_(maximumStorageMode),
         maximumStorageSize_(maximumStorageSize),
         maximumPatientCount_(maximumPatientCount),
         isReconstruct_(isReconstruct)
@@ -3134,8 +3148,24 @@
 
           if (!isReconstruct_)  // reconstruction should not affect recycling
           {
-            transaction.Recycle(maximumStorageSize_, maximumPatientCount_,
-                                instanceSize, hashPatient_ /* don't consider the current patient for recycling */);
+            if (maximumStorageMode_ == MaxStorageMode_Reject)
+            {
+              if (transaction.HasReachedMaxStorageSize(maximumStorageSize_, instanceSize))
+              {
+                storeStatus_ = StoreStatus_StorageFull;
+                throw OrthancException(ErrorCode_FullStorage, HttpStatus_507_InsufficientStorage, "Maximum storage size reached"); // throw to cancel the transaction
+              }
+              if (transaction.HasReachedMaxPatientCount(maximumPatientCount_, hashPatient_))
+              {
+                storeStatus_ = StoreStatus_StorageFull;
+                throw OrthancException(ErrorCode_FullStorage, HttpStatus_507_InsufficientStorage, "Maximum patient count reached");  // throw to cancel the transaction
+              }
+            }
+            else
+            {
+              transaction.Recycle(maximumStorageSize_, maximumPatientCount_,
+                                  instanceSize, hashPatient_ /* don't consider the current patient for recycling */);
+            }
           }  
      
           // Attach the files to the newly created instance
@@ -3349,7 +3379,7 @@
 
     Operations operations(instanceMetadata, dicomSummary, attachments, metadata, origin,
                           overwrite, hasTransferSyntax, transferSyntax, hasPixelDataOffset,
-                          pixelDataOffset, maximumStorageSize, maximumPatients, isReconstruct);
+                          pixelDataOffset, maximumStorageMode, maximumStorageSize, maximumPatients, isReconstruct);
     Apply(operations);
     return operations.GetStoreStatus();
   }