Mercurial > hg > orthanc
changeset 5402:bd3bae1525dd
merge
author | Alain Mazy <am@osimis.io> |
---|---|
date | Mon, 16 Oct 2023 17:31:50 +0200 |
parents | fc604681e6be (diff) b7e60d081b81 (current diff) |
children | 05cb668c5f3f |
files | NEWS |
diffstat | 6 files changed, 129 insertions(+), 25 deletions(-) [+] |
line wrap: on
line diff
--- a/NEWS Sat Oct 14 17:03:29 2023 +0200 +++ b/NEWS Mon Oct 16 17:31:50 2023 +0200 @@ -26,9 +26,10 @@ * Housekeeper: Introduced a 'sleep' to lower CPU usage when idle. * Support multiple values in SpecificCharacterSet in C-Find answers: https://discourse.orthanc-server.org/t/c-find-fails-on-unknown-specific-character-set-iso-2022-ir-6-iso-2022-ir-100/3947 +* When exporting a study archive, make sure to use the PatientName from the study and not from the patient + in case of PatientID collision. * Upgraded dependencies for static builds: - boost 1.83.0 - Version 1.12.1 (2023-07-04)
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestArchive.cpp Sat Oct 14 17:03:29 2023 +0200 +++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestArchive.cpp Mon Oct 16 17:31:50 2023 +0200 @@ -556,7 +556,7 @@ GetJobParameters(synchronous, extended, transcode, transferSyntax, priority, loaderThreads, body, DEFAULT_IS_EXTENDED); - std::unique_ptr<ArchiveJob> job(new ArchiveJob(context, IS_MEDIA, extended)); + std::unique_ptr<ArchiveJob> job(new ArchiveJob(context, IS_MEDIA, extended, ResourceType_Patient)); AddResourcesOfInterest(*job, body); if (transcode) @@ -627,7 +627,7 @@ extended = false; } - std::unique_ptr<ArchiveJob> job(new ArchiveJob(context, IS_MEDIA, extended)); + std::unique_ptr<ArchiveJob> job(new ArchiveJob(context, IS_MEDIA, extended, LEVEL)); job->AddResource(id, true, LEVEL); if (call.HasArgument(TRANSCODE)) @@ -679,7 +679,7 @@ GetJobParameters(synchronous, extended, transcode, transferSyntax, priority, loaderThreads, body, false /* by default, not extented */); - std::unique_ptr<ArchiveJob> job(new ArchiveJob(context, IS_MEDIA, extended)); + std::unique_ptr<ArchiveJob> job(new ArchiveJob(context, IS_MEDIA, extended, LEVEL)); job->AddResource(id, true, LEVEL); if (transcode)
--- a/OrthancServer/Sources/ServerJobs/ArchiveJob.cpp Sat Oct 14 17:03:29 2023 +0200 +++ b/OrthancServer/Sources/ServerJobs/ArchiveJob.cpp Mon Oct 16 17:31:50 2023 +0200 @@ -306,6 +306,91 @@ } }; + // This enum defines specific resource types to be used when exporting the archive. + // It defines if we should use the PatientInfo from the Patient or from the Study. + enum ArchiveResourceType + { + ArchiveResourceType_Patient = 0, + ArchiveResourceType_PatientInfoFromStudy = 1, + ArchiveResourceType_Study = 2, + ArchiveResourceType_Series = 3, + ArchiveResourceType_Instance = 4 + }; + + ResourceType GetResourceIdType(ArchiveResourceType type) + { + switch (type) + { + case ArchiveResourceType_Patient: + return ResourceType_Patient; + case ArchiveResourceType_PatientInfoFromStudy: // get the Patient tags from the Study id + return ResourceType_Study; + case ArchiveResourceType_Study: + return ResourceType_Study; + case ArchiveResourceType_Series: + return ResourceType_Series; + case ArchiveResourceType_Instance: + return ResourceType_Instance; + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + + ResourceType GetResourceLevel(ArchiveResourceType type) + { + switch (type) + { + case ArchiveResourceType_Patient: + return ResourceType_Patient; + case ArchiveResourceType_PatientInfoFromStudy: // this is actually the same level as the Patient + return ResourceType_Patient; + case ArchiveResourceType_Study: + return ResourceType_Study; + case ArchiveResourceType_Series: + return ResourceType_Series; + case ArchiveResourceType_Instance: + return ResourceType_Instance; + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + + ArchiveResourceType GetArchiveResourceType(ResourceType type) + { + switch (type) + { + case ResourceType_Patient: + return ArchiveResourceType_Patient; + case ArchiveResourceType_Study: + return ArchiveResourceType_PatientInfoFromStudy; + case ResourceType_Series: + return ArchiveResourceType_Series; + case ResourceType_Instance: + return ArchiveResourceType_Instance; + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + + ArchiveResourceType GetChildResourceType(ArchiveResourceType type) + { + switch (type) + { + case ArchiveResourceType_Patient: + case ArchiveResourceType_PatientInfoFromStudy: + return ArchiveResourceType_Study; + + case ArchiveResourceType_Study: + return ArchiveResourceType_Series; + + case ArchiveResourceType_Series: + return ArchiveResourceType_Instance; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + class ArchiveJob::ResourceIdentifiers : public boost::noncopyable { @@ -410,7 +495,7 @@ { } - virtual void Open(ResourceType level, + virtual void Open(ArchiveResourceType level, const std::string& publicId) = 0; virtual void Close() = 0; @@ -439,7 +524,7 @@ // A "NULL" value for ArchiveIndex indicates a non-expanded node typedef std::map<std::string, ArchiveIndex*> Resources; - ResourceType level_; + ArchiveResourceType level_; Resources resources_; // Only at patient/study/series level std::list<Instance> instances_; // Only at instance level @@ -447,7 +532,7 @@ void AddResourceToExpand(ServerIndex& index, const std::string& id) { - if (level_ == ResourceType_Instance) + if (level_ == ArchiveResourceType_Instance) { FileInfo tmp; int64_t revision; // ignored @@ -464,7 +549,7 @@ public: - explicit ArchiveIndex(ResourceType level) : + explicit ArchiveIndex(ArchiveResourceType level) : level_(level) { } @@ -482,14 +567,14 @@ void Add(ServerIndex& index, const ResourceIdentifiers& resource) { - const std::string& id = resource.GetIdentifier(level_); + const std::string& id = resource.GetIdentifier(GetResourceIdType(level_)); Resources::iterator previous = resources_.find(id); - if (level_ == ResourceType_Instance) + if (level_ == ArchiveResourceType_Instance) { AddResourceToExpand(index, id); } - else if (resource.GetLevel() == level_) + else if (resource.GetLevel() == GetResourceLevel(level_)) { // Mark this resource for further expansion if (previous != resources_.end()) @@ -519,7 +604,7 @@ void Expand(ServerIndex& index) { - if (level_ == ResourceType_Instance) + if (level_ == ArchiveResourceType_Instance) { // Expanding an instance node makes no sense return; @@ -553,7 +638,7 @@ void Apply(IArchiveVisitor& visitor) const { - if (level_ == ResourceType_Instance) + if (level_ == ArchiveResourceType_Instance) { for (std::list<Instance>::const_iterator it = instances_.begin(); it != instances_.end(); ++it) @@ -823,25 +908,29 @@ snprintf(instanceFormat_, sizeof(instanceFormat_) - 1, "%%08d.dcm"); } - virtual void Open(ResourceType level, + virtual void Open(ArchiveResourceType level, const std::string& publicId) ORTHANC_OVERRIDE { std::string path; DicomMap tags; - if (context_.GetIndex().GetMainDicomTags(tags, publicId, level, level)) + ResourceType resourceIdLevel = GetResourceIdType(level); + ResourceType interestLevel = (level == ArchiveResourceType_PatientInfoFromStudy ? ResourceType_Patient : resourceIdLevel); + + if (context_.GetIndex().GetMainDicomTags(tags, publicId, resourceIdLevel, interestLevel)) { switch (level) { - case ResourceType_Patient: + case ArchiveResourceType_Patient: + case ArchiveResourceType_PatientInfoFromStudy: path = GetTag(tags, DICOM_TAG_PATIENT_ID) + " " + GetTag(tags, DICOM_TAG_PATIENT_NAME); break; - case ResourceType_Study: + case ArchiveResourceType_Study: path = GetTag(tags, DICOM_TAG_ACCESSION_NUMBER) + " " + GetTag(tags, DICOM_TAG_STUDY_DESCRIPTION); break; - case ResourceType_Series: + case ArchiveResourceType_Series: { std::string modality = GetTag(tags, DICOM_TAG_MODALITY); path = modality + " " + GetTag(tags, DICOM_TAG_SERIES_DESCRIPTION); @@ -875,7 +964,7 @@ if (path.empty()) { - path = std::string("Unknown ") + EnumerationToString(level); + path = std::string("Unknown ") + EnumerationToString(GetResourceLevel(level)); } commands_.AddOpenDirectory(path.c_str()); @@ -911,7 +1000,7 @@ { } - virtual void Open(ResourceType level, + virtual void Open(ArchiveResourceType level, const std::string& publicId) ORTHANC_OVERRIDE { } @@ -1102,9 +1191,10 @@ ArchiveJob::ArchiveJob(ServerContext& context, bool isMedia, - bool enableExtendedSopClass) : + bool enableExtendedSopClass, + ResourceType jobLevel) : context_(context), - archive_(new ArchiveIndex(ResourceType_Patient)), // root + archive_(new ArchiveIndex(GetArchiveResourceType(jobLevel))), // root isMedia_(isMedia), enableExtendedSopClass_(enableExtendedSopClass), currentStep_(0),
--- a/OrthancServer/Sources/ServerJobs/ArchiveJob.h Sat Oct 14 17:03:29 2023 +0200 +++ b/OrthancServer/Sources/ServerJobs/ArchiveJob.h Mon Oct 16 17:31:50 2023 +0200 @@ -76,7 +76,8 @@ public: ArchiveJob(ServerContext& context, bool isMedia, - bool enableExtendedSopClass); + bool enableExtendedSopClass, + ResourceType jobLevel); virtual ~ArchiveJob();
--- a/OrthancServer/UnitTestsSources/ServerJobsTests.cpp Sat Oct 14 17:03:29 2023 +0200 +++ b/OrthancServer/UnitTestsSources/ServerJobsTests.cpp Mon Oct 16 17:31:50 2023 +0200 @@ -750,7 +750,7 @@ // ArchiveJob { - ArchiveJob job(GetContext(), false, false); + ArchiveJob job(GetContext(), false, false, ResourceType_Patient); ASSERT_FALSE(job.Serialize(s)); // Cannot serialize this }
--- a/TODO Sat Oct 14 17:03:29 2023 +0200 +++ b/TODO Mon Oct 16 17:31:50 2023 +0200 @@ -41,6 +41,19 @@ https://discourse.orthanc-server.org/t/performance-issue-when-adding-a-lot-of-jobs-in-the-queue/3915/2 Note: that might also be the right time to have a central jobs registry when working with multiple Orthanc instances on the same DB. +* Right now, some Stable events never occurs (e.g. when Orthanc is restarted before the event is triggered). + Since these events are used to e.g. generate dicom-web cache (or update it !), we should try + to make sure these events always happen. + - Generate the events when setting IsStable=true when starting an Orthanc (ok for SQLite) ? + - Also consider the use case of an Orthanc cluster that is being scaled-down just after one Orthanc instance + has received a few instances -> we can not only check for missing stable events at startup since no Orthanc will start. + We would need to maintain the list of "unstable" resources in DB instead of memory only. +* In prometheus metrics, implement Histograms or Exponential Histograms to measure durations. Right now, we only provide + "average" durations that are not very relevant + (https://opentelemetry.io/docs/specs/otel/metrics/data-model/#histogram) + - for job durations (+ have one histogram for each job) + - for HTTP request handling + - ... ============================ Documentation (Orthanc Book) @@ -131,7 +144,6 @@ https://discourse.orthanc-server.org/t/orthanc-convert-ybr-to-rgb-but-does-not-change-metadata/3533/9 * Implement a 'commit' route to force the Stable status earlier. https://discourse.orthanc-server.org/t/expediting-stability-of-a-dicom-study-new-api-endpoint/1684 - --------- Long-term