comparison 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
comparison
equal deleted inserted replaced
5060:e69a3ff39bc5 5061:e95fadefeb72
2771 Operations operations(dicom); 2771 Operations operations(dicom);
2772 Apply(operations); 2772 Apply(operations);
2773 } 2773 }
2774 2774
2775 2775
2776 static bool IsRecyclingNeeded(IDatabaseWrapper::ITransaction& transaction, 2776 bool StatelessDatabaseOperations::ReadWriteTransaction::HasReachedMaxStorageSize(uint64_t maximumStorageSize,
2777 uint64_t maximumStorageSize, 2777 uint64_t addedInstanceSize)
2778 unsigned int maximumPatients,
2779 uint64_t addedInstanceSize)
2780 { 2778 {
2781 if (maximumStorageSize != 0) 2779 if (maximumStorageSize != 0)
2782 { 2780 {
2783 if (maximumStorageSize < addedInstanceSize) 2781 if (maximumStorageSize < addedInstanceSize)
2784 { 2782 {
2786 boost::lexical_cast<std::string>(addedInstanceSize) + 2784 boost::lexical_cast<std::string>(addedInstanceSize) +
2787 " bytes in a storage area limited to " + 2785 " bytes in a storage area limited to " +
2788 boost::lexical_cast<std::string>(maximumStorageSize)); 2786 boost::lexical_cast<std::string>(maximumStorageSize));
2789 } 2787 }
2790 2788
2791 if (transaction.IsDiskSizeAbove(maximumStorageSize - addedInstanceSize)) 2789 if (transaction_.IsDiskSizeAbove(maximumStorageSize - addedInstanceSize))
2792 { 2790 {
2793 return true; 2791 return true;
2794 } 2792 }
2795 } 2793 }
2796 2794
2797 if (maximumPatients != 0) 2795 return false;
2798 { 2796 }
2799 uint64_t patientCount = transaction.GetResourcesCount(ResourceType_Patient); 2797
2800 if (patientCount > maximumPatients) 2798 bool StatelessDatabaseOperations::ReadWriteTransaction::HasReachedMaxPatientCount(unsigned int maximumPatientCount,
2801 { 2799 const std::string& patientId)
2802 return true; 2800 {
2803 } 2801 if (maximumPatientCount != 0)
2802 {
2803 uint64_t patientCount = transaction_.GetResourcesCount(ResourceType_Patient); // at this time, the new patient has already been added (as part of the transaction)
2804 return patientCount > maximumPatientCount;
2804 } 2805 }
2805 2806
2806 return false; 2807 return false;
2807 } 2808 }
2808 2809
2810 bool StatelessDatabaseOperations::ReadWriteTransaction::IsRecyclingNeeded(uint64_t maximumStorageSize,
2811 unsigned int maximumPatients,
2812 uint64_t addedInstanceSize,
2813 const std::string& newPatientId)
2814 {
2815 return HasReachedMaxStorageSize(maximumStorageSize, addedInstanceSize)
2816 || HasReachedMaxPatientCount(maximumPatients, newPatientId);
2817 }
2809 2818
2810 void StatelessDatabaseOperations::ReadWriteTransaction::Recycle(uint64_t maximumStorageSize, 2819 void StatelessDatabaseOperations::ReadWriteTransaction::Recycle(uint64_t maximumStorageSize,
2811 unsigned int maximumPatients, 2820 unsigned int maximumPatients,
2812 uint64_t addedInstanceSize, 2821 uint64_t addedInstanceSize,
2813 const std::string& newPatientId) 2822 const std::string& newPatientId)
2814 { 2823 {
2815 // TODO - Performance: Avoid calls to "IsRecyclingNeeded()" 2824 // TODO - Performance: Avoid calls to "IsRecyclingNeeded()"
2816 2825
2817 if (IsRecyclingNeeded(transaction_, maximumStorageSize, maximumPatients, addedInstanceSize)) 2826 if (IsRecyclingNeeded(maximumStorageSize, maximumPatients, addedInstanceSize, newPatientId))
2818 { 2827 {
2819 // Check whether other DICOM instances from this patient are 2828 // Check whether other DICOM instances from this patient are
2820 // already stored 2829 // already stored
2821 int64_t patientToAvoid; 2830 int64_t patientToAvoid;
2822 bool hasPatientToAvoid; 2831 bool hasPatientToAvoid;
2852 } 2861 }
2853 2862
2854 LOG(TRACE) << "Recycling one patient"; 2863 LOG(TRACE) << "Recycling one patient";
2855 transaction_.DeleteResource(patientToRecycle); 2864 transaction_.DeleteResource(patientToRecycle);
2856 2865
2857 if (!IsRecyclingNeeded(transaction_, maximumStorageSize, maximumPatients, addedInstanceSize)) 2866 if (!IsRecyclingNeeded(maximumStorageSize, maximumPatients, addedInstanceSize, newPatientId))
2858 { 2867 {
2859 // OK, we're done 2868 // OK, we're done
2860 return; 2869 return;
2861 } 2870 }
2862 } 2871 }
2863 } 2872 }
2864 } 2873 }
2865 2874
2866 2875
2867 void StatelessDatabaseOperations::StandaloneRecycling(uint64_t maximumStorageSize, 2876 void StatelessDatabaseOperations::StandaloneRecycling(MaxStorageMode maximumStorageMode,
2877 uint64_t maximumStorageSize,
2868 unsigned int maximumPatientCount) 2878 unsigned int maximumPatientCount)
2869 { 2879 {
2870 class Operations : public IReadWriteOperations 2880 class Operations : public IReadWriteOperations
2871 { 2881 {
2872 private: 2882 private:
2873 uint64_t maximumStorageSize_; 2883 uint64_t maximumStorageSize_;
2874 unsigned int maximumPatientCount_; 2884 unsigned int maximumPatientCount_;
2875 2885
2876 public: 2886 public:
2877 Operations(uint64_t maximumStorageSize, 2887 Operations(uint64_t maximumStorageSize,
2878 unsigned int maximumPatientCount) : 2888 unsigned int maximumPatientCount) :
2879 maximumStorageSize_(maximumStorageSize), 2889 maximumStorageSize_(maximumStorageSize),
2885 { 2895 {
2886 transaction.Recycle(maximumStorageSize_, maximumPatientCount_, 0, ""); 2896 transaction.Recycle(maximumStorageSize_, maximumPatientCount_, 0, "");
2887 } 2897 }
2888 }; 2898 };
2889 2899
2890 if (maximumStorageSize != 0 || 2900 if (maximumStorageMode == MaxStorageMode_Recycle
2891 maximumPatientCount != 0) 2901 && (maximumStorageSize != 0 || maximumPatientCount != 0))
2892 { 2902 {
2893 Operations operations(maximumStorageSize, maximumPatientCount); 2903 Operations operations(maximumStorageSize, maximumPatientCount);
2894 Apply(operations); 2904 Apply(operations);
2895 } 2905 }
2896 } 2906 }
2904 bool overwrite, 2914 bool overwrite,
2905 bool hasTransferSyntax, 2915 bool hasTransferSyntax,
2906 DicomTransferSyntax transferSyntax, 2916 DicomTransferSyntax transferSyntax,
2907 bool hasPixelDataOffset, 2917 bool hasPixelDataOffset,
2908 uint64_t pixelDataOffset, 2918 uint64_t pixelDataOffset,
2919 MaxStorageMode maximumStorageMode,
2909 uint64_t maximumStorageSize, 2920 uint64_t maximumStorageSize,
2910 unsigned int maximumPatients, 2921 unsigned int maximumPatients,
2911 bool isReconstruct) 2922 bool isReconstruct)
2912 { 2923 {
2913 class Operations : public IReadWriteOperations 2924 class Operations : public IReadWriteOperations
2922 bool overwrite_; 2933 bool overwrite_;
2923 bool hasTransferSyntax_; 2934 bool hasTransferSyntax_;
2924 DicomTransferSyntax transferSyntax_; 2935 DicomTransferSyntax transferSyntax_;
2925 bool hasPixelDataOffset_; 2936 bool hasPixelDataOffset_;
2926 uint64_t pixelDataOffset_; 2937 uint64_t pixelDataOffset_;
2938 MaxStorageMode maximumStorageMode_;
2927 uint64_t maximumStorageSize_; 2939 uint64_t maximumStorageSize_;
2928 unsigned int maximumPatientCount_; 2940 unsigned int maximumPatientCount_;
2929 bool isReconstruct_; 2941 bool isReconstruct_;
2930 2942
2931 // Auto-computed fields 2943 // Auto-computed fields
3024 bool overwrite, 3036 bool overwrite,
3025 bool hasTransferSyntax, 3037 bool hasTransferSyntax,
3026 DicomTransferSyntax transferSyntax, 3038 DicomTransferSyntax transferSyntax,
3027 bool hasPixelDataOffset, 3039 bool hasPixelDataOffset,
3028 uint64_t pixelDataOffset, 3040 uint64_t pixelDataOffset,
3041 MaxStorageMode maximumStorageMode,
3029 uint64_t maximumStorageSize, 3042 uint64_t maximumStorageSize,
3030 unsigned int maximumPatientCount, 3043 unsigned int maximumPatientCount,
3031 bool isReconstruct) : 3044 bool isReconstruct) :
3032 storeStatus_(StoreStatus_Failure), 3045 storeStatus_(StoreStatus_Failure),
3033 instanceMetadata_(instanceMetadata), 3046 instanceMetadata_(instanceMetadata),
3038 overwrite_(overwrite), 3051 overwrite_(overwrite),
3039 hasTransferSyntax_(hasTransferSyntax), 3052 hasTransferSyntax_(hasTransferSyntax),
3040 transferSyntax_(transferSyntax), 3053 transferSyntax_(transferSyntax),
3041 hasPixelDataOffset_(hasPixelDataOffset), 3054 hasPixelDataOffset_(hasPixelDataOffset),
3042 pixelDataOffset_(pixelDataOffset), 3055 pixelDataOffset_(pixelDataOffset),
3056 maximumStorageMode_(maximumStorageMode),
3043 maximumStorageSize_(maximumStorageSize), 3057 maximumStorageSize_(maximumStorageSize),
3044 maximumPatientCount_(maximumPatientCount), 3058 maximumPatientCount_(maximumPatientCount),
3045 isReconstruct_(isReconstruct) 3059 isReconstruct_(isReconstruct)
3046 { 3060 {
3047 hasExpectedInstances_ = ComputeExpectedNumberOfInstances(expectedInstances_, dicomSummary); 3061 hasExpectedInstances_ = ComputeExpectedNumberOfInstances(expectedInstances_, dicomSummary);
3132 instanceSize += it->GetCompressedSize(); 3146 instanceSize += it->GetCompressedSize();
3133 } 3147 }
3134 3148
3135 if (!isReconstruct_) // reconstruction should not affect recycling 3149 if (!isReconstruct_) // reconstruction should not affect recycling
3136 { 3150 {
3137 transaction.Recycle(maximumStorageSize_, maximumPatientCount_, 3151 if (maximumStorageMode_ == MaxStorageMode_Reject)
3138 instanceSize, hashPatient_ /* don't consider the current patient for recycling */); 3152 {
3153 if (transaction.HasReachedMaxStorageSize(maximumStorageSize_, instanceSize))
3154 {
3155 storeStatus_ = StoreStatus_StorageFull;
3156 throw OrthancException(ErrorCode_FullStorage, HttpStatus_507_InsufficientStorage, "Maximum storage size reached"); // throw to cancel the transaction
3157 }
3158 if (transaction.HasReachedMaxPatientCount(maximumPatientCount_, hashPatient_))
3159 {
3160 storeStatus_ = StoreStatus_StorageFull;
3161 throw OrthancException(ErrorCode_FullStorage, HttpStatus_507_InsufficientStorage, "Maximum patient count reached"); // throw to cancel the transaction
3162 }
3163 }
3164 else
3165 {
3166 transaction.Recycle(maximumStorageSize_, maximumPatientCount_,
3167 instanceSize, hashPatient_ /* don't consider the current patient for recycling */);
3168 }
3139 } 3169 }
3140 3170
3141 // Attach the files to the newly created instance 3171 // Attach the files to the newly created instance
3142 for (Attachments::const_iterator it = attachments_.begin(); 3172 for (Attachments::const_iterator it = attachments_.begin();
3143 it != attachments_.end(); ++it) 3173 it != attachments_.end(); ++it)
3347 }; 3377 };
3348 3378
3349 3379
3350 Operations operations(instanceMetadata, dicomSummary, attachments, metadata, origin, 3380 Operations operations(instanceMetadata, dicomSummary, attachments, metadata, origin,
3351 overwrite, hasTransferSyntax, transferSyntax, hasPixelDataOffset, 3381 overwrite, hasTransferSyntax, transferSyntax, hasPixelDataOffset,
3352 pixelDataOffset, maximumStorageSize, maximumPatients, isReconstruct); 3382 pixelDataOffset, maximumStorageMode, maximumStorageSize, maximumPatients, isReconstruct);
3353 Apply(operations); 3383 Apply(operations);
3354 return operations.GetStoreStatus(); 3384 return operations.GetStoreStatus();
3355 } 3385 }
3356 3386
3357 3387