# HG changeset patch # User Alain Mazy # Date 1684760401 -7200 # Node ID 5053a10da5a23589c76855ab44c171f6c2295679 # Parent e0e2aee4453e861f066bfd293242b6b9a7db0ad6 Fix orphan files remaining in storage when working with MaximumStorageSize diff -r e0e2aee4453e -r 5053a10da5a2 NEWS --- a/NEWS Wed May 10 12:52:35 2023 +0200 +++ b/NEWS Mon May 22 15:00:01 2023 +0200 @@ -10,6 +10,8 @@ * Modality worklists plugin: allow searching on private tags (exact match only) * Upgraded dependencies for static builds: - boost 1.82.0 +* Fix orphan files remaining in storage when working with MaximumStorageSize + (https://discourse.orthanc-server.org/t/issue-with-deleting-incoming-dicoms-when-maximumstoragesize-is-reached/3510) Version 1.12.0 (2023-04-14) diff -r e0e2aee4453e -r 5053a10da5a2 OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp --- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp Wed May 10 12:52:35 2023 +0200 +++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp Mon May 22 15:00:01 2023 +0200 @@ -3098,317 +3098,295 @@ virtual void Apply(ReadWriteTransaction& transaction) ORTHANC_OVERRIDE { - try + IDatabaseWrapper::CreateInstanceResult status; + int64_t instanceId; + + bool isNewInstance = transaction.CreateInstance(status, instanceId, hashPatient_, + hashStudy_, hashSeries_, hashInstance_); + + if (isReconstruct_ && isNewInstance) { - IDatabaseWrapper::CreateInstanceResult status; - int64_t instanceId; - - bool isNewInstance = transaction.CreateInstance(status, instanceId, hashPatient_, - hashStudy_, hashSeries_, hashInstance_); - - if (isReconstruct_ && isNewInstance) - { - // In case of reconstruct, we just want to modify the attachments and some metadata like the TransferSyntex - // The DicomTags and many metadata have already been updated before we get here in ReconstructInstance - throw OrthancException(ErrorCode_InternalError, "New instance while reconstructing; this should not happen."); - } - - // Check whether this instance is already stored - if (!isNewInstance && !isReconstruct_) + // In case of reconstruct, we just want to modify the attachments and some metadata like the TransferSyntex + // The DicomTags and many metadata have already been updated before we get here in ReconstructInstance + throw OrthancException(ErrorCode_InternalError, "New instance while reconstructing; this should not happen."); + } + + // Check whether this instance is already stored + if (!isNewInstance && !isReconstruct_) + { + // The instance already exists + if (overwrite_) { - // The instance already exists - if (overwrite_) + // Overwrite the old instance + LOG(INFO) << "Overwriting instance: " << hashInstance_; + transaction.DeleteResource(instanceId); + + // Re-create the instance, now that the old one is removed + if (!transaction.CreateInstance(status, instanceId, hashPatient_, + hashStudy_, hashSeries_, hashInstance_)) { - // Overwrite the old instance - LOG(INFO) << "Overwriting instance: " << hashInstance_; - transaction.DeleteResource(instanceId); - - // Re-create the instance, now that the old one is removed - if (!transaction.CreateInstance(status, instanceId, hashPatient_, - hashStudy_, hashSeries_, hashInstance_)) - { - throw OrthancException(ErrorCode_InternalError, "No new instance while overwriting; this should not happen."); - } - } - else - { - // Do nothing if the instance already exists and overwriting is disabled - transaction.GetAllMetadata(instanceMetadata_, instanceId); - storeStatus_ = StoreStatus_AlreadyStored; - return; + throw OrthancException(ErrorCode_InternalError, "No new instance while overwriting; this should not happen."); } } - - - if (!isReconstruct_) // don't signal new resources if this is a reconstruction + else + { + // Do nothing if the instance already exists and overwriting is disabled + transaction.GetAllMetadata(instanceMetadata_, instanceId); + storeStatus_ = StoreStatus_AlreadyStored; + return; + } + } + + + if (!isReconstruct_) // don't signal new resources if this is a reconstruction + { + // Warn about the creation of new resources. The order must be + // from instance to patient. + + // NB: In theory, could be sped up by grouping the underlying + // calls to "transaction.LogChange()". However, this would only have an + // impact when new patient/study/series get created, which + // occurs far less often that creating new instances. The + // positive impact looks marginal in practice. + transaction.LogChange(instanceId, ChangeType_NewInstance, ResourceType_Instance, hashInstance_); + + if (status.isNewSeries_) { - // Warn about the creation of new resources. The order must be - // from instance to patient. - - // NB: In theory, could be sped up by grouping the underlying - // calls to "transaction.LogChange()". However, this would only have an - // impact when new patient/study/series get created, which - // occurs far less often that creating new instances. The - // positive impact looks marginal in practice. - transaction.LogChange(instanceId, ChangeType_NewInstance, ResourceType_Instance, hashInstance_); - - if (status.isNewSeries_) - { - transaction.LogChange(status.seriesId_, ChangeType_NewSeries, ResourceType_Series, hashSeries_); - } - - if (status.isNewStudy_) - { - transaction.LogChange(status.studyId_, ChangeType_NewStudy, ResourceType_Study, hashStudy_); - } - - if (status.isNewPatient_) - { - transaction.LogChange(status.patientId_, ChangeType_NewPatient, ResourceType_Patient, hashPatient_); - } - } + transaction.LogChange(status.seriesId_, ChangeType_NewSeries, ResourceType_Series, hashSeries_); + } + + if (status.isNewStudy_) + { + transaction.LogChange(status.studyId_, ChangeType_NewStudy, ResourceType_Study, hashStudy_); + } - // Ensure there is enough room in the storage for the new instance - uint64_t instanceSize = 0; - for (Attachments::const_iterator it = attachments_.begin(); - it != attachments_.end(); ++it) + if (status.isNewPatient_) + { + transaction.LogChange(status.patientId_, ChangeType_NewPatient, ResourceType_Patient, hashPatient_); + } + } + + // Ensure there is enough room in the storage for the new instance + uint64_t instanceSize = 0; + for (Attachments::const_iterator it = attachments_.begin(); + it != attachments_.end(); ++it) + { + instanceSize += it->GetCompressedSize(); + } + + if (!isReconstruct_) // reconstruction should not affect recycling + { + if (maximumStorageMode_ == MaxStorageMode_Reject) { - instanceSize += it->GetCompressedSize(); - } - - if (!isReconstruct_) // reconstruction should not affect recycling - { - if (maximumStorageMode_ == MaxStorageMode_Reject) + if (transaction.HasReachedMaxStorageSize(maximumStorageSize_, instanceSize)) { - 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 - } + 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 + } + else + { + transaction.Recycle(maximumStorageSize_, maximumPatientCount_, + instanceSize, hashPatient_ /* don't consider the current patient for recycling */); + } + } + + // Attach the files to the newly created instance + for (Attachments::const_iterator it = attachments_.begin(); + it != attachments_.end(); ++it) + { + if (isReconstruct_) + { + // we are replacing attachments during a reconstruction + transaction.DeleteAttachment(instanceId, it->GetContentType()); + } + + transaction.AddAttachment(instanceId, *it, 0 /* this is the first revision */); + } + + if (!isReconstruct_) + { + ResourcesContent content(true /* new resource, metadata can be set */); + + // Attach the user-specified metadata (in case of reconstruction, metadata_ contains all past metadata, including the system ones we want to keep) + for (MetadataMap::const_iterator + it = metadata_.begin(); it != metadata_.end(); ++it) + { + switch (it->first.first) { - transaction.Recycle(maximumStorageSize_, maximumPatientCount_, - instanceSize, hashPatient_ /* don't consider the current patient for recycling */); + case ResourceType_Patient: + content.AddMetadata(status.patientId_, it->first.second, it->second); + break; + + case ResourceType_Study: + content.AddMetadata(status.studyId_, it->first.second, it->second); + break; + + case ResourceType_Series: + content.AddMetadata(status.seriesId_, it->first.second, it->second); + break; + + case ResourceType_Instance: + SetInstanceMetadata(content, instanceMetadata_, instanceId, + it->first.second, it->second); + break; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); } - } - - // Attach the files to the newly created instance - for (Attachments::const_iterator it = attachments_.begin(); - it != attachments_.end(); ++it) - { - if (isReconstruct_) - { - // we are replacing attachments during a reconstruction - transaction.DeleteAttachment(instanceId, it->GetContentType()); - } - - transaction.AddAttachment(instanceId, *it, 0 /* this is the first revision */); } if (!isReconstruct_) { - ResourcesContent content(true /* new resource, metadata can be set */); - - // Attach the user-specified metadata (in case of reconstruction, metadata_ contains all past metadata, including the system ones we want to keep) - for (MetadataMap::const_iterator - it = metadata_.begin(); it != metadata_.end(); ++it) + // Populate the tags of the newly-created resources + content.AddResource(instanceId, ResourceType_Instance, dicomSummary_); + SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Instance)); // New in Orthanc 1.11.0 + SetMainDicomSequenceMetadata(content, instanceId, dicomSummary_, ResourceType_Instance); // new in Orthanc 1.11.1 + + if (status.isNewSeries_) { - switch (it->first.first) - { - case ResourceType_Patient: - content.AddMetadata(status.patientId_, it->first.second, it->second); - break; - - case ResourceType_Study: - content.AddMetadata(status.studyId_, it->first.second, it->second); - break; - - case ResourceType_Series: - content.AddMetadata(status.seriesId_, it->first.second, it->second); - break; - - case ResourceType_Instance: - SetInstanceMetadata(content, instanceMetadata_, instanceId, - it->first.second, it->second); - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } + content.AddResource(status.seriesId_, ResourceType_Series, dicomSummary_); + content.AddMetadata(status.seriesId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Series)); // New in Orthanc 1.11.0 + SetMainDicomSequenceMetadata(content, status.seriesId_, dicomSummary_, ResourceType_Series); // new in Orthanc 1.11.1 } - if (!isReconstruct_) + if (status.isNewStudy_) { - // Populate the tags of the newly-created resources - content.AddResource(instanceId, ResourceType_Instance, dicomSummary_); - SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Instance)); // New in Orthanc 1.11.0 - SetMainDicomSequenceMetadata(content, instanceId, dicomSummary_, ResourceType_Instance); // new in Orthanc 1.11.1 - - if (status.isNewSeries_) - { - content.AddResource(status.seriesId_, ResourceType_Series, dicomSummary_); - content.AddMetadata(status.seriesId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Series)); // New in Orthanc 1.11.0 - SetMainDicomSequenceMetadata(content, status.seriesId_, dicomSummary_, ResourceType_Series); // new in Orthanc 1.11.1 - } - - if (status.isNewStudy_) - { - content.AddResource(status.studyId_, ResourceType_Study, dicomSummary_); - content.AddMetadata(status.studyId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Study)); // New in Orthanc 1.11.0 - SetMainDicomSequenceMetadata(content, status.studyId_, dicomSummary_, ResourceType_Study); // new in Orthanc 1.11.1 - } - - if (status.isNewPatient_) - { - content.AddResource(status.patientId_, ResourceType_Patient, dicomSummary_); - content.AddMetadata(status.patientId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Patient)); // New in Orthanc 1.11.0 - SetMainDicomSequenceMetadata(content, status.patientId_, dicomSummary_, ResourceType_Patient); // new in Orthanc 1.11.1 - } - - // Attach the auto-computed metadata for the patient/study/series levels - std::string now = SystemToolbox::GetNowIsoString(true /* use UTC time (not local time) */); - content.AddMetadata(status.seriesId_, MetadataType_LastUpdate, now); - content.AddMetadata(status.studyId_, MetadataType_LastUpdate, now); - content.AddMetadata(status.patientId_, MetadataType_LastUpdate, now); - - if (status.isNewSeries_) + content.AddResource(status.studyId_, ResourceType_Study, dicomSummary_); + content.AddMetadata(status.studyId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Study)); // New in Orthanc 1.11.0 + SetMainDicomSequenceMetadata(content, status.studyId_, dicomSummary_, ResourceType_Study); // new in Orthanc 1.11.1 + } + + if (status.isNewPatient_) + { + content.AddResource(status.patientId_, ResourceType_Patient, dicomSummary_); + content.AddMetadata(status.patientId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Patient)); // New in Orthanc 1.11.0 + SetMainDicomSequenceMetadata(content, status.patientId_, dicomSummary_, ResourceType_Patient); // new in Orthanc 1.11.1 + } + + // Attach the auto-computed metadata for the patient/study/series levels + std::string now = SystemToolbox::GetNowIsoString(true /* use UTC time (not local time) */); + content.AddMetadata(status.seriesId_, MetadataType_LastUpdate, now); + content.AddMetadata(status.studyId_, MetadataType_LastUpdate, now); + content.AddMetadata(status.patientId_, MetadataType_LastUpdate, now); + + if (status.isNewSeries_) + { + if (hasExpectedInstances_) { - if (hasExpectedInstances_) - { - content.AddMetadata(status.seriesId_, MetadataType_Series_ExpectedNumberOfInstances, - boost::lexical_cast(expectedInstances_)); - } - - // New in Orthanc 1.9.0 - content.AddMetadata(status.seriesId_, MetadataType_RemoteAet, - origin_.GetRemoteAetC()); - } - // Attach the auto-computed metadata for the instance level, - // reflecting these additions into the input metadata map - SetInstanceMetadata(content, instanceMetadata_, instanceId, - MetadataType_Instance_ReceptionDate, now); - SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_RemoteAet, - origin_.GetRemoteAetC()); - SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_Instance_Origin, - EnumerationToString(origin_.GetRequestOrigin())); - - std::string s; - - if (origin_.LookupRemoteIp(s)) - { - // New in Orthanc 1.4.0 - SetInstanceMetadata(content, instanceMetadata_, instanceId, - MetadataType_Instance_RemoteIp, s); + content.AddMetadata(status.seriesId_, MetadataType_Series_ExpectedNumberOfInstances, + boost::lexical_cast(expectedInstances_)); } - if (origin_.LookupCalledAet(s)) - { - // New in Orthanc 1.4.0 - SetInstanceMetadata(content, instanceMetadata_, instanceId, - MetadataType_Instance_CalledAet, s); - } - - if (origin_.LookupHttpUsername(s)) - { - // New in Orthanc 1.4.0 - SetInstanceMetadata(content, instanceMetadata_, instanceId, - MetadataType_Instance_HttpUsername, s); - } + // New in Orthanc 1.9.0 + content.AddMetadata(status.seriesId_, MetadataType_RemoteAet, + origin_.GetRemoteAetC()); + } + // Attach the auto-computed metadata for the instance level, + // reflecting these additions into the input metadata map + SetInstanceMetadata(content, instanceMetadata_, instanceId, + MetadataType_Instance_ReceptionDate, now); + SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_RemoteAet, + origin_.GetRemoteAetC()); + SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_Instance_Origin, + EnumerationToString(origin_.GetRequestOrigin())); + + std::string s; + + if (origin_.LookupRemoteIp(s)) + { + // New in Orthanc 1.4.0 + SetInstanceMetadata(content, instanceMetadata_, instanceId, + MetadataType_Instance_RemoteIp, s); + } + + if (origin_.LookupCalledAet(s)) + { + // New in Orthanc 1.4.0 + SetInstanceMetadata(content, instanceMetadata_, instanceId, + MetadataType_Instance_CalledAet, s); + } + + if (origin_.LookupHttpUsername(s)) + { + // New in Orthanc 1.4.0 + SetInstanceMetadata(content, instanceMetadata_, instanceId, + MetadataType_Instance_HttpUsername, s); } - - // Following metadatas are also updated if reconstructing the instance. - // They might be missing since they have been introduced along Orthanc versions. - - if (hasTransferSyntax_) - { - // New in Orthanc 1.2.0 - SetInstanceMetadata(content, instanceMetadata_, instanceId, - MetadataType_Instance_TransferSyntax, - GetTransferSyntaxUid(transferSyntax_)); - } - - if (hasPixelDataOffset_) - { - // New in Orthanc 1.9.1 - SetInstanceMetadata(content, instanceMetadata_, instanceId, - MetadataType_Instance_PixelDataOffset, - boost::lexical_cast(pixelDataOffset_)); - } - - const DicomValue* value; - if ((value = dicomSummary_.TestAndGetValue(DICOM_TAG_SOP_CLASS_UID)) != NULL && - !value->IsNull() && + } + + // Following metadatas are also updated if reconstructing the instance. + // They might be missing since they have been introduced along Orthanc versions. + + if (hasTransferSyntax_) + { + // New in Orthanc 1.2.0 + SetInstanceMetadata(content, instanceMetadata_, instanceId, + MetadataType_Instance_TransferSyntax, + GetTransferSyntaxUid(transferSyntax_)); + } + + if (hasPixelDataOffset_) + { + // New in Orthanc 1.9.1 + SetInstanceMetadata(content, instanceMetadata_, instanceId, + MetadataType_Instance_PixelDataOffset, + boost::lexical_cast(pixelDataOffset_)); + } + + const DicomValue* value; + if ((value = dicomSummary_.TestAndGetValue(DICOM_TAG_SOP_CLASS_UID)) != NULL && + !value->IsNull() && + !value->IsBinary()) + { + SetInstanceMetadata(content, instanceMetadata_, instanceId, + MetadataType_Instance_SopClassUid, value->GetContent()); + } + + + if ((value = dicomSummary_.TestAndGetValue(DICOM_TAG_INSTANCE_NUMBER)) != NULL || + (value = dicomSummary_.TestAndGetValue(DICOM_TAG_IMAGE_INDEX)) != NULL) + { + if (!value->IsNull() && !value->IsBinary()) { SetInstanceMetadata(content, instanceMetadata_, instanceId, - MetadataType_Instance_SopClassUid, value->GetContent()); - } - - - if ((value = dicomSummary_.TestAndGetValue(DICOM_TAG_INSTANCE_NUMBER)) != NULL || - (value = dicomSummary_.TestAndGetValue(DICOM_TAG_IMAGE_INDEX)) != NULL) - { - if (!value->IsNull() && - !value->IsBinary()) - { - SetInstanceMetadata(content, instanceMetadata_, instanceId, - MetadataType_Instance_IndexInSeries, Toolbox::StripSpaces(value->GetContent())); - } - } - - - transaction.SetResourcesContent(content); - } - - - // Check whether the series of this new instance is now completed - int64_t expectedNumberOfInstances; - if (ComputeExpectedNumberOfInstances(expectedNumberOfInstances, dicomSummary_)) - { - SeriesStatus seriesStatus = transaction.GetSeriesStatus(status.seriesId_, expectedNumberOfInstances); - if (seriesStatus == SeriesStatus_Complete) - { - transaction.LogChange(status.seriesId_, ChangeType_CompletedSeries, ResourceType_Series, hashSeries_); + MetadataType_Instance_IndexInSeries, Toolbox::StripSpaces(value->GetContent())); } } - - transaction.LogChange(status.seriesId_, ChangeType_NewChildInstance, ResourceType_Series, hashSeries_); - transaction.LogChange(status.studyId_, ChangeType_NewChildInstance, ResourceType_Study, hashStudy_); - transaction.LogChange(status.patientId_, ChangeType_NewChildInstance, ResourceType_Patient, hashPatient_); - - // Mark the parent resources of this instance as unstable - transaction.GetTransactionContext().MarkAsUnstable(status.seriesId_, ResourceType_Series, hashSeries_); - transaction.GetTransactionContext().MarkAsUnstable(status.studyId_, ResourceType_Study, hashStudy_); - transaction.GetTransactionContext().MarkAsUnstable(status.patientId_, ResourceType_Patient, hashPatient_); - transaction.GetTransactionContext().SignalAttachmentsAdded(instanceSize); - - storeStatus_ = StoreStatus_Success; + + + transaction.SetResourcesContent(content); } - catch (OrthancException& e) + + + // Check whether the series of this new instance is now completed + int64_t expectedNumberOfInstances; + if (ComputeExpectedNumberOfInstances(expectedNumberOfInstances, dicomSummary_)) { - if (e.GetErrorCode() == ErrorCode_DatabaseCannotSerialize) - { - throw; // the transaction has failed -> do not commit the current transaction (and retry) - } - else + SeriesStatus seriesStatus = transaction.GetSeriesStatus(status.seriesId_, expectedNumberOfInstances); + if (seriesStatus == SeriesStatus_Complete) { - LOG(ERROR) << "EXCEPTION [" << e.What() << " - " << e.GetDetails() << "]"; - - if (e.GetErrorCode() == ErrorCode_FullStorage) - { - throw; // do not commit the current transaction - } - - // this is an expected failure, exit normaly and commit the current transaction - storeStatus_ = StoreStatus_Failure; + transaction.LogChange(status.seriesId_, ChangeType_CompletedSeries, ResourceType_Series, hashSeries_); } } + + transaction.LogChange(status.seriesId_, ChangeType_NewChildInstance, ResourceType_Series, hashSeries_); + transaction.LogChange(status.studyId_, ChangeType_NewChildInstance, ResourceType_Study, hashStudy_); + transaction.LogChange(status.patientId_, ChangeType_NewChildInstance, ResourceType_Patient, hashPatient_); + + // Mark the parent resources of this instance as unstable + transaction.GetTransactionContext().MarkAsUnstable(status.seriesId_, ResourceType_Series, hashSeries_); + transaction.GetTransactionContext().MarkAsUnstable(status.studyId_, ResourceType_Study, hashStudy_); + transaction.GetTransactionContext().MarkAsUnstable(status.patientId_, ResourceType_Patient, hashPatient_); + transaction.GetTransactionContext().SignalAttachmentsAdded(instanceSize); + + storeStatus_ = StoreStatus_Success; } }; @@ -3416,8 +3394,24 @@ Operations operations(instanceMetadata, dicomSummary, attachments, metadata, origin, overwrite, hasTransferSyntax, transferSyntax, hasPixelDataOffset, pixelDataOffset, maximumStorageMode, maximumStorageSize, maximumPatients, isReconstruct); - Apply(operations); - return operations.GetStoreStatus(); + + try + { + Apply(operations); + return operations.GetStoreStatus(); + } + catch (OrthancException& e) + { + if (e.GetErrorCode() == ErrorCode_FullStorage) + { + return StoreStatus_StorageFull; + } + else + { + // the transaction has failed -> do not commit the current transaction (and retry) + throw; + } + } } @@ -3475,7 +3469,7 @@ int64_t resourceId; if (!transaction.LookupResource(resourceId, resourceType, publicId_)) { - status_ = StoreStatus_Failure; // Inexistent resource + throw OrthancException(ErrorCode_InexistentItem, HttpStatus_404_NotFound); } else { diff -r e0e2aee4453e -r 5053a10da5a2 OrthancServer/Sources/ServerContext.cpp --- a/OrthancServer/Sources/ServerContext.cpp Wed May 10 12:52:35 2023 +0200 +++ b/OrthancServer/Sources/ServerContext.cpp Mon May 22 15:00:01 2023 +0200 @@ -688,8 +688,12 @@ break; case StoreStatus_Failure: - LOG(ERROR) << "Store failure"; - break; + LOG(ERROR) << "Unknown store failure"; + throw OrthancException(ErrorCode_InternalError, HttpStatus_500_InternalServerError); + + case StoreStatus_StorageFull: + LOG(ERROR) << "Storage full"; + throw OrthancException(ErrorCode_FullStorage, HttpStatus_507_InsufficientStorage); default: // This should never happen