changeset 5224:feba2b0e91bc

Fix a crash in /tools/reconstruct triggered by the Housekeeper plugin when only changing the StorageCompression.
author Alain Mazy <am@osimis.io>
date Mon, 03 Apr 2023 22:19:42 +0200
parents a47b24f231d0
children 5874e5dd9a38
files NEWS OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp OrthancServer/Sources/ServerToolbox.cpp
diffstat 3 files changed, 80 insertions(+), 66 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Mon Apr 03 15:13:58 2023 +0200
+++ b/NEWS	Mon Apr 03 22:19:42 2023 +0200
@@ -20,6 +20,8 @@
 * Fix issue 214: VOILUTSequence is not returned in Wado-RS
 * Fix /tools/reset crashing when ExtraMainDicomTags were defined
 * Fix Housekeeper plugin infinite loop if Orthanc is empty.
+* Fix a crash in /tools/reconstruct triggered by the Housekeeper plugin 
+  when only changing the StorageCompression.
 
 
 Version 1.11.3 (2023-02-03)
--- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp	Mon Apr 03 15:13:58 2023 +0200
+++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp	Mon Apr 03 22:19:42 2023 +0200
@@ -2956,6 +2956,10 @@
                                       MetadataType metadata,
                                       const std::string& value)
       {
+        if (metadata == 15)
+        {
+          LOG(INFO) << "toto";
+        }
         content.AddMetadata(instance, metadata, value);
         instanceMetadata[metadata] = value;
       }
@@ -3081,13 +3085,21 @@
         {
           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 (!transaction.CreateInstance(status, instanceId, hashPatient_,
-                                          hashStudy_, hashSeries_, hashInstance_))
+          if (!isNewInstance && !isReconstruct_)
           {
             // The instance already exists
-        
             if (overwrite_)
             {
               // Overwrite the old instance
@@ -3098,7 +3110,7 @@
               if (!transaction.CreateInstance(status, instanceId, hashPatient_,
                                               hashStudy_, hashSeries_, hashInstance_))
               {
-                throw OrthancException(ErrorCode_InternalError);
+                throw OrthancException(ErrorCode_InternalError, "No new instance while overwriting; this should not happen.");
               }
             }
             else
@@ -3173,14 +3185,19 @@
           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)
@@ -3209,62 +3226,52 @@
               }
             }
 
-            // 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_)
+            if (!isReconstruct_)
             {
-              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_)
+              // 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.AddMetadata(status.seriesId_, MetadataType_Series_ExpectedNumberOfInstances,
-                                    boost::lexical_cast<std::string>(expectedInstances_));
+                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
               }
 
-              // New in Orthanc 1.9.0
-              content.AddMetadata(status.seriesId_, MetadataType_RemoteAet,
-                                  origin_.GetRemoteAetC());
-            }
-
-            if (hasTransferSyntax_)
-            {
-              // New in Orthanc 1.2.0
-              SetInstanceMetadata(content, instanceMetadata_, instanceId,
-                                  MetadataType_Instance_TransferSyntax,
-                                  GetTransferSyntaxUid(transferSyntax_));
-            }
-
-            if (!isReconstruct_) // don't change origin metadata
-            {        
+              // 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_)
+                {
+                  content.AddMetadata(status.seriesId_, MetadataType_Series_ExpectedNumberOfInstances,
+                                      boost::lexical_cast<std::string>(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,
@@ -3298,6 +3305,17 @@
               }
             }
 
+            // 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
--- a/OrthancServer/Sources/ServerToolbox.cpp	Mon Apr 03 15:13:58 2023 +0200
+++ b/OrthancServer/Sources/ServerToolbox.cpp	Mon Apr 03 22:19:42 2023 +0200
@@ -281,14 +281,8 @@
           std::string resultPublicId;  // ignored
           std::unique_ptr<DicomInstanceToStore> dicomInstancetoStore(DicomInstanceToStore::CreateFromParsedDicomFile(locker.GetDicom()));
 
-          context.GetIndex().GetAllMetadata(instanceMetadata, *it, ResourceType_Instance);
-          
-          for (InstanceMetadata::const_iterator itm = instanceMetadata.begin();
-              itm != instanceMetadata.end(); ++itm)
-          {
-            dicomInstancetoStore->AddMetadata(ResourceType_Instance, itm->first, itm->second);
-          }
-
+          // TODO: TranscodeAndStore and specifically ServerIndex::Store have been "poluted" by the isReconstruct parameter
+          // we should very likely refactor it
           context.TranscodeAndStore(resultPublicId, dicomInstancetoStore.get(), StoreInstanceMode_OverwriteDuplicate, true);
         }
       }