Mercurial > hg > orthanc
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 |