comparison OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp @ 4988:8fba26292a9f

Housekeeper plugin: finalizing + integration tests ok
author Alain Mazy <am@osimis.io>
date Sat, 30 Apr 2022 19:39:40 +0200
parents 304514ce84ee
children 877bc3b96476
comparison
equal deleted inserted replaced
4986:a25e74fad379 4988:8fba26292a9f
2848 bool hasTransferSyntax, 2848 bool hasTransferSyntax,
2849 DicomTransferSyntax transferSyntax, 2849 DicomTransferSyntax transferSyntax,
2850 bool hasPixelDataOffset, 2850 bool hasPixelDataOffset,
2851 uint64_t pixelDataOffset, 2851 uint64_t pixelDataOffset,
2852 uint64_t maximumStorageSize, 2852 uint64_t maximumStorageSize,
2853 unsigned int maximumPatients) 2853 unsigned int maximumPatients,
2854 bool isReconstruct)
2854 { 2855 {
2855 class Operations : public IReadWriteOperations 2856 class Operations : public IReadWriteOperations
2856 { 2857 {
2857 private: 2858 private:
2858 StoreStatus storeStatus_; 2859 StoreStatus storeStatus_;
2866 DicomTransferSyntax transferSyntax_; 2867 DicomTransferSyntax transferSyntax_;
2867 bool hasPixelDataOffset_; 2868 bool hasPixelDataOffset_;
2868 uint64_t pixelDataOffset_; 2869 uint64_t pixelDataOffset_;
2869 uint64_t maximumStorageSize_; 2870 uint64_t maximumStorageSize_;
2870 unsigned int maximumPatientCount_; 2871 unsigned int maximumPatientCount_;
2872 bool isReconstruct_;
2871 2873
2872 // Auto-computed fields 2874 // Auto-computed fields
2873 bool hasExpectedInstances_; 2875 bool hasExpectedInstances_;
2874 int64_t expectedInstances_; 2876 int64_t expectedInstances_;
2875 std::string hashPatient_; 2877 std::string hashPatient_;
2953 bool hasTransferSyntax, 2955 bool hasTransferSyntax,
2954 DicomTransferSyntax transferSyntax, 2956 DicomTransferSyntax transferSyntax,
2955 bool hasPixelDataOffset, 2957 bool hasPixelDataOffset,
2956 uint64_t pixelDataOffset, 2958 uint64_t pixelDataOffset,
2957 uint64_t maximumStorageSize, 2959 uint64_t maximumStorageSize,
2958 unsigned int maximumPatientCount) : 2960 unsigned int maximumPatientCount,
2961 bool isReconstruct) :
2959 storeStatus_(StoreStatus_Failure), 2962 storeStatus_(StoreStatus_Failure),
2960 instanceMetadata_(instanceMetadata), 2963 instanceMetadata_(instanceMetadata),
2961 dicomSummary_(dicomSummary), 2964 dicomSummary_(dicomSummary),
2962 attachments_(attachments), 2965 attachments_(attachments),
2963 metadata_(metadata), 2966 metadata_(metadata),
2966 hasTransferSyntax_(hasTransferSyntax), 2969 hasTransferSyntax_(hasTransferSyntax),
2967 transferSyntax_(transferSyntax), 2970 transferSyntax_(transferSyntax),
2968 hasPixelDataOffset_(hasPixelDataOffset), 2971 hasPixelDataOffset_(hasPixelDataOffset),
2969 pixelDataOffset_(pixelDataOffset), 2972 pixelDataOffset_(pixelDataOffset),
2970 maximumStorageSize_(maximumStorageSize), 2973 maximumStorageSize_(maximumStorageSize),
2971 maximumPatientCount_(maximumPatientCount) 2974 maximumPatientCount_(maximumPatientCount),
2975 isReconstruct_(isReconstruct)
2972 { 2976 {
2973 hasExpectedInstances_ = ComputeExpectedNumberOfInstances(expectedInstances_, dicomSummary); 2977 hasExpectedInstances_ = ComputeExpectedNumberOfInstances(expectedInstances_, dicomSummary);
2974 2978
2975 instanceMetadata_.clear(); 2979 instanceMetadata_.clear();
2976 2980
3020 return; 3024 return;
3021 } 3025 }
3022 } 3026 }
3023 3027
3024 3028
3025 // Warn about the creation of new resources. The order must be 3029 if (!isReconstruct_) // don't signal new resources if this is a reconstruction
3026 // from instance to patient. 3030 {
3027 3031 // Warn about the creation of new resources. The order must be
3028 // NB: In theory, could be sped up by grouping the underlying 3032 // from instance to patient.
3029 // calls to "transaction.LogChange()". However, this would only have an 3033
3030 // impact when new patient/study/series get created, which 3034 // NB: In theory, could be sped up by grouping the underlying
3031 // occurs far less often that creating new instances. The 3035 // calls to "transaction.LogChange()". However, this would only have an
3032 // positive impact looks marginal in practice. 3036 // impact when new patient/study/series get created, which
3033 transaction.LogChange(instanceId, ChangeType_NewInstance, ResourceType_Instance, hashInstance_); 3037 // occurs far less often that creating new instances. The
3034 3038 // positive impact looks marginal in practice.
3035 if (status.isNewSeries_) 3039 transaction.LogChange(instanceId, ChangeType_NewInstance, ResourceType_Instance, hashInstance_);
3036 { 3040
3037 transaction.LogChange(status.seriesId_, ChangeType_NewSeries, ResourceType_Series, hashSeries_); 3041 if (status.isNewSeries_)
3038 } 3042 {
3039 3043 transaction.LogChange(status.seriesId_, ChangeType_NewSeries, ResourceType_Series, hashSeries_);
3040 if (status.isNewStudy_) 3044 }
3041 { 3045
3042 transaction.LogChange(status.studyId_, ChangeType_NewStudy, ResourceType_Study, hashStudy_); 3046 if (status.isNewStudy_)
3043 } 3047 {
3044 3048 transaction.LogChange(status.studyId_, ChangeType_NewStudy, ResourceType_Study, hashStudy_);
3045 if (status.isNewPatient_) 3049 }
3046 { 3050
3047 transaction.LogChange(status.patientId_, ChangeType_NewPatient, ResourceType_Patient, hashPatient_); 3051 if (status.isNewPatient_)
3048 } 3052 {
3049 3053 transaction.LogChange(status.patientId_, ChangeType_NewPatient, ResourceType_Patient, hashPatient_);
3054 }
3055 }
3050 3056
3051 // Ensure there is enough room in the storage for the new instance 3057 // Ensure there is enough room in the storage for the new instance
3052 uint64_t instanceSize = 0; 3058 uint64_t instanceSize = 0;
3053 for (Attachments::const_iterator it = attachments_.begin(); 3059 for (Attachments::const_iterator it = attachments_.begin();
3054 it != attachments_.end(); ++it) 3060 it != attachments_.end(); ++it)
3055 { 3061 {
3056 instanceSize += it->GetCompressedSize(); 3062 instanceSize += it->GetCompressedSize();
3057 } 3063 }
3058 3064
3059 transaction.Recycle(maximumStorageSize_, maximumPatientCount_, 3065 if (!isReconstruct_) // reconstruction should not affect recycling
3060 instanceSize, hashPatient_ /* don't consider the current patient for recycling */); 3066 {
3061 3067 transaction.Recycle(maximumStorageSize_, maximumPatientCount_,
3068 instanceSize, hashPatient_ /* don't consider the current patient for recycling */);
3069 }
3062 3070
3063 // Attach the files to the newly created instance 3071 // Attach the files to the newly created instance
3064 for (Attachments::const_iterator it = attachments_.begin(); 3072 for (Attachments::const_iterator it = attachments_.begin();
3065 it != attachments_.end(); ++it) 3073 it != attachments_.end(); ++it)
3066 { 3074 {
3068 } 3076 }
3069 3077
3070 3078
3071 { 3079 {
3072 ResourcesContent content(true /* new resource, metadata can be set */); 3080 ResourcesContent content(true /* new resource, metadata can be set */);
3073 3081
3074 // Populate the tags of the newly-created resources 3082
3075 3083 // Attach the user-specified metadata (in case of reconstruction, metadata_ contains all past metadata, including the system ones we want to keep)
3076 content.AddResource(instanceId, ResourceType_Instance, dicomSummary_);
3077 content.AddMetadata(instanceId, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Instance)); // New in Orthanc 1.11.0
3078
3079 if (status.isNewSeries_)
3080 {
3081 content.AddResource(status.seriesId_, ResourceType_Series, dicomSummary_);
3082 content.AddMetadata(status.seriesId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Series)); // New in Orthanc 1.11.0
3083 }
3084
3085 if (status.isNewStudy_)
3086 {
3087 content.AddResource(status.studyId_, ResourceType_Study, dicomSummary_);
3088 content.AddMetadata(status.studyId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Study)); // New in Orthanc 1.11.0
3089 }
3090
3091 if (status.isNewPatient_)
3092 {
3093 content.AddResource(status.patientId_, ResourceType_Patient, dicomSummary_);
3094 content.AddMetadata(status.patientId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Patient)); // New in Orthanc 1.11.0
3095 }
3096
3097
3098 // Attach the user-specified metadata
3099
3100 for (MetadataMap::const_iterator 3084 for (MetadataMap::const_iterator
3101 it = metadata_.begin(); it != metadata_.end(); ++it) 3085 it = metadata_.begin(); it != metadata_.end(); ++it)
3102 { 3086 {
3103 switch (it->first.first) 3087 switch (it->first.first)
3104 { 3088 {
3122 default: 3106 default:
3123 throw OrthancException(ErrorCode_ParameterOutOfRange); 3107 throw OrthancException(ErrorCode_ParameterOutOfRange);
3124 } 3108 }
3125 } 3109 }
3126 3110
3127 3111 // Populate the tags of the newly-created resources
3112
3113 content.AddResource(instanceId, ResourceType_Instance, dicomSummary_);
3114 SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Instance)); // New in Orthanc 1.11.0
3115
3116 if (status.isNewSeries_)
3117 {
3118 content.AddResource(status.seriesId_, ResourceType_Series, dicomSummary_);
3119 content.AddMetadata(status.seriesId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Series)); // New in Orthanc 1.11.0
3120 }
3121
3122 if (status.isNewStudy_)
3123 {
3124 content.AddResource(status.studyId_, ResourceType_Study, dicomSummary_);
3125 content.AddMetadata(status.studyId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Study)); // New in Orthanc 1.11.0
3126 }
3127
3128 if (status.isNewPatient_)
3129 {
3130 content.AddResource(status.patientId_, ResourceType_Patient, dicomSummary_);
3131 content.AddMetadata(status.patientId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Patient)); // New in Orthanc 1.11.0
3132 }
3133
3128 // Attach the auto-computed metadata for the patient/study/series levels 3134 // Attach the auto-computed metadata for the patient/study/series levels
3129 std::string now = SystemToolbox::GetNowIsoString(true /* use UTC time (not local time) */); 3135 std::string now = SystemToolbox::GetNowIsoString(true /* use UTC time (not local time) */);
3130 content.AddMetadata(status.seriesId_, MetadataType_LastUpdate, now); 3136 content.AddMetadata(status.seriesId_, MetadataType_LastUpdate, now);
3131 content.AddMetadata(status.studyId_, MetadataType_LastUpdate, now); 3137 content.AddMetadata(status.studyId_, MetadataType_LastUpdate, now);
3132 content.AddMetadata(status.patientId_, MetadataType_LastUpdate, now); 3138 content.AddMetadata(status.patientId_, MetadataType_LastUpdate, now);
3142 // New in Orthanc 1.9.0 3148 // New in Orthanc 1.9.0
3143 content.AddMetadata(status.seriesId_, MetadataType_RemoteAet, 3149 content.AddMetadata(status.seriesId_, MetadataType_RemoteAet,
3144 origin_.GetRemoteAetC()); 3150 origin_.GetRemoteAetC());
3145 } 3151 }
3146 3152
3147
3148 // Attach the auto-computed metadata for the instance level,
3149 // reflecting these additions into the input metadata map
3150 SetInstanceMetadata(content, instanceMetadata_, instanceId,
3151 MetadataType_Instance_ReceptionDate, now);
3152 SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_RemoteAet,
3153 origin_.GetRemoteAetC());
3154 SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_Instance_Origin,
3155 EnumerationToString(origin_.GetRequestOrigin()));
3156
3157
3158 if (hasTransferSyntax_) 3153 if (hasTransferSyntax_)
3159 { 3154 {
3160 // New in Orthanc 1.2.0 3155 // New in Orthanc 1.2.0
3161 SetInstanceMetadata(content, instanceMetadata_, instanceId, 3156 SetInstanceMetadata(content, instanceMetadata_, instanceId,
3162 MetadataType_Instance_TransferSyntax, 3157 MetadataType_Instance_TransferSyntax,
3163 GetTransferSyntaxUid(transferSyntax_)); 3158 GetTransferSyntaxUid(transferSyntax_));
3164 } 3159 }
3165 3160
3166 { 3161 if (!isReconstruct_) // don't change origin metadata
3162 {
3163 // Attach the auto-computed metadata for the instance level,
3164 // reflecting these additions into the input metadata map
3165 SetInstanceMetadata(content, instanceMetadata_, instanceId,
3166 MetadataType_Instance_ReceptionDate, now);
3167 SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_RemoteAet,
3168 origin_.GetRemoteAetC());
3169 SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_Instance_Origin,
3170 EnumerationToString(origin_.GetRequestOrigin()));
3171
3167 std::string s; 3172 std::string s;
3168 3173
3169 if (origin_.LookupRemoteIp(s)) 3174 if (origin_.LookupRemoteIp(s))
3170 { 3175 {
3171 // New in Orthanc 1.4.0 3176 // New in Orthanc 1.4.0
3268 }; 3273 };
3269 3274
3270 3275
3271 Operations operations(instanceMetadata, dicomSummary, attachments, metadata, origin, 3276 Operations operations(instanceMetadata, dicomSummary, attachments, metadata, origin,
3272 overwrite, hasTransferSyntax, transferSyntax, hasPixelDataOffset, 3277 overwrite, hasTransferSyntax, transferSyntax, hasPixelDataOffset,
3273 pixelDataOffset, maximumStorageSize, maximumPatients); 3278 pixelDataOffset, maximumStorageSize, maximumPatients, isReconstruct);
3274 Apply(operations); 3279 Apply(operations);
3275 return operations.GetStoreStatus(); 3280 return operations.GetStoreStatus();
3276 } 3281 }
3277 3282
3278 3283