comparison OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp @ 5635:0e16e677fe64

fixed broken /instances/../tags after reconstructing studies when IngestTranscoding has changed
author Alain Mazy <am@orthanc.team>
date Tue, 21 May 2024 17:09:57 +0200
parents b2a97dfd719f
children f7adfb22e20e
comparison
equal deleted inserted replaced
5633:5db4ed395d81 5635:0e16e677fe64
3340 } 3340 }
3341 3341
3342 transaction.AddAttachment(instanceId, *it, 0 /* this is the first revision */); 3342 transaction.AddAttachment(instanceId, *it, 0 /* this is the first revision */);
3343 } 3343 }
3344 3344
3345 ResourcesContent content(true /* new resource, metadata can be set */);
3346
3347 // Attach the user-specified metadata (in case of reconstruction, metadata_ contains all past metadata, including the system ones we want to keep)
3348 for (MetadataMap::const_iterator
3349 it = metadata_.begin(); it != metadata_.end(); ++it)
3350 {
3351 switch (it->first.first)
3352 {
3353 case ResourceType_Patient:
3354 content.AddMetadata(status.patientId_, it->first.second, it->second);
3355 break;
3356
3357 case ResourceType_Study:
3358 content.AddMetadata(status.studyId_, it->first.second, it->second);
3359 break;
3360
3361 case ResourceType_Series:
3362 content.AddMetadata(status.seriesId_, it->first.second, it->second);
3363 break;
3364
3365 case ResourceType_Instance:
3366 SetInstanceMetadata(content, instanceMetadata_, instanceId,
3367 it->first.second, it->second);
3368 break;
3369
3370 default:
3371 throw OrthancException(ErrorCode_ParameterOutOfRange);
3372 }
3373 }
3374
3345 if (!isReconstruct_) 3375 if (!isReconstruct_)
3346 { 3376 {
3347 ResourcesContent content(true /* new resource, metadata can be set */); 3377 // Populate the tags of the newly-created resources
3348 3378 content.AddResource(instanceId, ResourceType_Instance, dicomSummary_);
3349 // Attach the user-specified metadata (in case of reconstruction, metadata_ contains all past metadata, including the system ones we want to keep) 3379 SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Instance)); // New in Orthanc 1.11.0
3350 for (MetadataMap::const_iterator 3380 SetMainDicomSequenceMetadata(content, instanceId, dicomSummary_, ResourceType_Instance); // new in Orthanc 1.11.1
3351 it = metadata_.begin(); it != metadata_.end(); ++it) 3381
3352 { 3382 if (status.isNewSeries_)
3353 switch (it->first.first) 3383 {
3384 content.AddResource(status.seriesId_, ResourceType_Series, dicomSummary_);
3385 content.AddMetadata(status.seriesId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Series)); // New in Orthanc 1.11.0
3386 SetMainDicomSequenceMetadata(content, status.seriesId_, dicomSummary_, ResourceType_Series); // new in Orthanc 1.11.1
3387 }
3388
3389 if (status.isNewStudy_)
3390 {
3391 content.AddResource(status.studyId_, ResourceType_Study, dicomSummary_);
3392 content.AddMetadata(status.studyId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Study)); // New in Orthanc 1.11.0
3393 SetMainDicomSequenceMetadata(content, status.studyId_, dicomSummary_, ResourceType_Study); // new in Orthanc 1.11.1
3394 }
3395
3396 if (status.isNewPatient_)
3397 {
3398 content.AddResource(status.patientId_, ResourceType_Patient, dicomSummary_);
3399 content.AddMetadata(status.patientId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Patient)); // New in Orthanc 1.11.0
3400 SetMainDicomSequenceMetadata(content, status.patientId_, dicomSummary_, ResourceType_Patient); // new in Orthanc 1.11.1
3401 }
3402
3403 // Attach the auto-computed metadata for the patient/study/series levels
3404 std::string now = SystemToolbox::GetNowIsoString(true /* use UTC time (not local time) */);
3405 content.AddMetadata(status.seriesId_, MetadataType_LastUpdate, now);
3406 content.AddMetadata(status.studyId_, MetadataType_LastUpdate, now);
3407 content.AddMetadata(status.patientId_, MetadataType_LastUpdate, now);
3408
3409 if (status.isNewSeries_)
3410 {
3411 if (hasExpectedInstances_)
3354 { 3412 {
3355 case ResourceType_Patient: 3413 content.AddMetadata(status.seriesId_, MetadataType_Series_ExpectedNumberOfInstances,
3356 content.AddMetadata(status.patientId_, it->first.second, it->second); 3414 boost::lexical_cast<std::string>(expectedInstances_));
3357 break;
3358
3359 case ResourceType_Study:
3360 content.AddMetadata(status.studyId_, it->first.second, it->second);
3361 break;
3362
3363 case ResourceType_Series:
3364 content.AddMetadata(status.seriesId_, it->first.second, it->second);
3365 break;
3366
3367 case ResourceType_Instance:
3368 SetInstanceMetadata(content, instanceMetadata_, instanceId,
3369 it->first.second, it->second);
3370 break;
3371
3372 default:
3373 throw OrthancException(ErrorCode_ParameterOutOfRange);
3374 } 3415 }
3375 } 3416
3376 3417 // New in Orthanc 1.9.0
3377 if (!isReconstruct_) 3418 content.AddMetadata(status.seriesId_, MetadataType_RemoteAet,
3378 { 3419 origin_.GetRemoteAetC());
3379 // Populate the tags of the newly-created resources 3420 }
3380 content.AddResource(instanceId, ResourceType_Instance, dicomSummary_); 3421 // Attach the auto-computed metadata for the instance level,
3381 SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Instance)); // New in Orthanc 1.11.0 3422 // reflecting these additions into the input metadata map
3382 SetMainDicomSequenceMetadata(content, instanceId, dicomSummary_, ResourceType_Instance); // new in Orthanc 1.11.1 3423 SetInstanceMetadata(content, instanceMetadata_, instanceId,
3383 3424 MetadataType_Instance_ReceptionDate, now);
3384 if (status.isNewSeries_) 3425 SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_RemoteAet,
3426 origin_.GetRemoteAetC());
3427 SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_Instance_Origin,
3428 EnumerationToString(origin_.GetRequestOrigin()));
3429
3430 std::string s;
3431
3432 if (origin_.LookupRemoteIp(s))
3433 {
3434 // New in Orthanc 1.4.0
3435 SetInstanceMetadata(content, instanceMetadata_, instanceId,
3436 MetadataType_Instance_RemoteIp, s);
3437 }
3438
3439 if (origin_.LookupCalledAet(s))
3440 {
3441 // New in Orthanc 1.4.0
3442 SetInstanceMetadata(content, instanceMetadata_, instanceId,
3443 MetadataType_Instance_CalledAet, s);
3444 }
3445
3446 if (origin_.LookupHttpUsername(s))
3447 {
3448 // New in Orthanc 1.4.0
3449 SetInstanceMetadata(content, instanceMetadata_, instanceId,
3450 MetadataType_Instance_HttpUsername, s);
3451 }
3452 }
3453
3454 // Following metadatas are also updated if reconstructing the instance.
3455 // They might be missing since they have been introduced along Orthanc versions.
3456
3457 if (hasTransferSyntax_)
3458 {
3459 // New in Orthanc 1.2.0
3460 SetInstanceMetadata(content, instanceMetadata_, instanceId,
3461 MetadataType_Instance_TransferSyntax,
3462 GetTransferSyntaxUid(transferSyntax_));
3463 }
3464
3465 if (hasPixelDataOffset_)
3466 {
3467 // New in Orthanc 1.9.1
3468 SetInstanceMetadata(content, instanceMetadata_, instanceId,
3469 MetadataType_Instance_PixelDataOffset,
3470 boost::lexical_cast<std::string>(pixelDataOffset_));
3471
3472 // New in Orthanc 1.12.1
3473 if (dicomSummary_.GuessPixelDataValueRepresentation(transferSyntax_) != pixelDataVR_)
3474 {
3475 // Store the VR of pixel data if it doesn't comply with the standard
3476 SetInstanceMetadata(content, instanceMetadata_, instanceId,
3477 MetadataType_Instance_PixelDataVR,
3478 EnumerationToString(pixelDataVR_));
3479 }
3480 }
3481
3482 const DicomValue* value;
3483 if ((value = dicomSummary_.TestAndGetValue(DICOM_TAG_SOP_CLASS_UID)) != NULL &&
3484 !value->IsNull() &&
3485 !value->IsBinary())
3486 {
3487 SetInstanceMetadata(content, instanceMetadata_, instanceId,
3488 MetadataType_Instance_SopClassUid, value->GetContent());
3489 }
3490
3491
3492 if ((value = dicomSummary_.TestAndGetValue(DICOM_TAG_INSTANCE_NUMBER)) != NULL ||
3493 (value = dicomSummary_.TestAndGetValue(DICOM_TAG_IMAGE_INDEX)) != NULL)
3494 {
3495 if (!value->IsNull() &&
3496 !value->IsBinary())
3497 {
3498 SetInstanceMetadata(content, instanceMetadata_, instanceId,
3499 MetadataType_Instance_IndexInSeries, Toolbox::StripSpaces(value->GetContent()));
3500 }
3501 }
3502
3503
3504 transaction.SetResourcesContent(content);
3505
3506
3507 if (!isReconstruct_) // a reconstruct shall not trigger any events
3508 {
3509 // Check whether the series of this new instance is now completed
3510 int64_t expectedNumberOfInstances;
3511 if (ComputeExpectedNumberOfInstances(expectedNumberOfInstances, dicomSummary_))
3512 {
3513 SeriesStatus seriesStatus = transaction.GetSeriesStatus(status.seriesId_, expectedNumberOfInstances);
3514 if (seriesStatus == SeriesStatus_Complete)
3385 { 3515 {
3386 content.AddResource(status.seriesId_, ResourceType_Series, dicomSummary_); 3516 transaction.LogChange(status.seriesId_, ChangeType_CompletedSeries, ResourceType_Series, hashSeries_);
3387 content.AddMetadata(status.seriesId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Series)); // New in Orthanc 1.11.0
3388 SetMainDicomSequenceMetadata(content, status.seriesId_, dicomSummary_, ResourceType_Series); // new in Orthanc 1.11.1
3389 } 3517 }
3390 3518 }
3391 if (status.isNewStudy_) 3519
3392 { 3520 transaction.LogChange(status.seriesId_, ChangeType_NewChildInstance, ResourceType_Series, hashSeries_);
3393 content.AddResource(status.studyId_, ResourceType_Study, dicomSummary_); 3521 transaction.LogChange(status.studyId_, ChangeType_NewChildInstance, ResourceType_Study, hashStudy_);
3394 content.AddMetadata(status.studyId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Study)); // New in Orthanc 1.11.0 3522 transaction.LogChange(status.patientId_, ChangeType_NewChildInstance, ResourceType_Patient, hashPatient_);
3395 SetMainDicomSequenceMetadata(content, status.studyId_, dicomSummary_, ResourceType_Study); // new in Orthanc 1.11.1 3523
3396 } 3524 // Mark the parent resources of this instance as unstable
3397 3525 transaction.GetTransactionContext().MarkAsUnstable(ResourceType_Series, status.seriesId_, hashSeries_);
3398 if (status.isNewPatient_) 3526 transaction.GetTransactionContext().MarkAsUnstable(ResourceType_Study, status.studyId_, hashStudy_);
3399 { 3527 transaction.GetTransactionContext().MarkAsUnstable(ResourceType_Patient, status.patientId_, hashPatient_);
3400 content.AddResource(status.patientId_, ResourceType_Patient, dicomSummary_); 3528 }
3401 content.AddMetadata(status.patientId_, MetadataType_MainDicomTagsSignature, DicomMap::GetMainDicomTagsSignature(ResourceType_Patient)); // New in Orthanc 1.11.0 3529
3402 SetMainDicomSequenceMetadata(content, status.patientId_, dicomSummary_, ResourceType_Patient); // new in Orthanc 1.11.1
3403 }
3404
3405 // Attach the auto-computed metadata for the patient/study/series levels
3406 std::string now = SystemToolbox::GetNowIsoString(true /* use UTC time (not local time) */);
3407 content.AddMetadata(status.seriesId_, MetadataType_LastUpdate, now);
3408 content.AddMetadata(status.studyId_, MetadataType_LastUpdate, now);
3409 content.AddMetadata(status.patientId_, MetadataType_LastUpdate, now);
3410
3411 if (status.isNewSeries_)
3412 {
3413 if (hasExpectedInstances_)
3414 {
3415 content.AddMetadata(status.seriesId_, MetadataType_Series_ExpectedNumberOfInstances,
3416 boost::lexical_cast<std::string>(expectedInstances_));
3417 }
3418
3419 // New in Orthanc 1.9.0
3420 content.AddMetadata(status.seriesId_, MetadataType_RemoteAet,
3421 origin_.GetRemoteAetC());
3422 }
3423 // Attach the auto-computed metadata for the instance level,
3424 // reflecting these additions into the input metadata map
3425 SetInstanceMetadata(content, instanceMetadata_, instanceId,
3426 MetadataType_Instance_ReceptionDate, now);
3427 SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_RemoteAet,
3428 origin_.GetRemoteAetC());
3429 SetInstanceMetadata(content, instanceMetadata_, instanceId, MetadataType_Instance_Origin,
3430 EnumerationToString(origin_.GetRequestOrigin()));
3431
3432 std::string s;
3433
3434 if (origin_.LookupRemoteIp(s))
3435 {
3436 // New in Orthanc 1.4.0
3437 SetInstanceMetadata(content, instanceMetadata_, instanceId,
3438 MetadataType_Instance_RemoteIp, s);
3439 }
3440
3441 if (origin_.LookupCalledAet(s))
3442 {
3443 // New in Orthanc 1.4.0
3444 SetInstanceMetadata(content, instanceMetadata_, instanceId,
3445 MetadataType_Instance_CalledAet, s);
3446 }
3447
3448 if (origin_.LookupHttpUsername(s))
3449 {
3450 // New in Orthanc 1.4.0
3451 SetInstanceMetadata(content, instanceMetadata_, instanceId,
3452 MetadataType_Instance_HttpUsername, s);
3453 }
3454 }
3455
3456 // Following metadatas are also updated if reconstructing the instance.
3457 // They might be missing since they have been introduced along Orthanc versions.
3458
3459 if (hasTransferSyntax_)
3460 {
3461 // New in Orthanc 1.2.0
3462 SetInstanceMetadata(content, instanceMetadata_, instanceId,
3463 MetadataType_Instance_TransferSyntax,
3464 GetTransferSyntaxUid(transferSyntax_));
3465 }
3466
3467 if (hasPixelDataOffset_)
3468 {
3469 // New in Orthanc 1.9.1
3470 SetInstanceMetadata(content, instanceMetadata_, instanceId,
3471 MetadataType_Instance_PixelDataOffset,
3472 boost::lexical_cast<std::string>(pixelDataOffset_));
3473
3474 // New in Orthanc 1.12.1
3475 if (dicomSummary_.GuessPixelDataValueRepresentation(transferSyntax_) != pixelDataVR_)
3476 {
3477 // Store the VR of pixel data if it doesn't comply with the standard
3478 SetInstanceMetadata(content, instanceMetadata_, instanceId,
3479 MetadataType_Instance_PixelDataVR,
3480 EnumerationToString(pixelDataVR_));
3481 }
3482 }
3483
3484 const DicomValue* value;
3485 if ((value = dicomSummary_.TestAndGetValue(DICOM_TAG_SOP_CLASS_UID)) != NULL &&
3486 !value->IsNull() &&
3487 !value->IsBinary())
3488 {
3489 SetInstanceMetadata(content, instanceMetadata_, instanceId,
3490 MetadataType_Instance_SopClassUid, value->GetContent());
3491 }
3492
3493
3494 if ((value = dicomSummary_.TestAndGetValue(DICOM_TAG_INSTANCE_NUMBER)) != NULL ||
3495 (value = dicomSummary_.TestAndGetValue(DICOM_TAG_IMAGE_INDEX)) != NULL)
3496 {
3497 if (!value->IsNull() &&
3498 !value->IsBinary())
3499 {
3500 SetInstanceMetadata(content, instanceMetadata_, instanceId,
3501 MetadataType_Instance_IndexInSeries, Toolbox::StripSpaces(value->GetContent()));
3502 }
3503 }
3504
3505
3506 transaction.SetResourcesContent(content);
3507 }
3508
3509
3510 // Check whether the series of this new instance is now completed
3511 int64_t expectedNumberOfInstances;
3512 if (ComputeExpectedNumberOfInstances(expectedNumberOfInstances, dicomSummary_))
3513 {
3514 SeriesStatus seriesStatus = transaction.GetSeriesStatus(status.seriesId_, expectedNumberOfInstances);
3515 if (seriesStatus == SeriesStatus_Complete)
3516 {
3517 transaction.LogChange(status.seriesId_, ChangeType_CompletedSeries, ResourceType_Series, hashSeries_);
3518 }
3519 }
3520
3521 transaction.LogChange(status.seriesId_, ChangeType_NewChildInstance, ResourceType_Series, hashSeries_);
3522 transaction.LogChange(status.studyId_, ChangeType_NewChildInstance, ResourceType_Study, hashStudy_);
3523 transaction.LogChange(status.patientId_, ChangeType_NewChildInstance, ResourceType_Patient, hashPatient_);
3524
3525 // Mark the parent resources of this instance as unstable
3526 transaction.GetTransactionContext().MarkAsUnstable(ResourceType_Series, status.seriesId_, hashSeries_);
3527 transaction.GetTransactionContext().MarkAsUnstable(ResourceType_Study, status.studyId_, hashStudy_);
3528 transaction.GetTransactionContext().MarkAsUnstable(ResourceType_Patient, status.patientId_, hashPatient_);
3529 transaction.GetTransactionContext().SignalAttachmentsAdded(instanceSize); 3530 transaction.GetTransactionContext().SignalAttachmentsAdded(instanceSize);
3530 3531 storeStatus_ = StoreStatus_Success;
3531 storeStatus_ = StoreStatus_Success;
3532 } 3532 }
3533 }; 3533 };
3534 3534
3535 3535
3536 Operations operations(instanceMetadata, dicomSummary, attachments, metadata, origin, overwrite, 3536 Operations operations(instanceMetadata, dicomSummary, attachments, metadata, origin, overwrite,