comparison OrthancServer/Sources/ResourceFinder.cpp @ 5688:d0a264b803f1 find-refactoring

first implementation of database paging
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 09 Jul 2024 15:36:28 +0200
parents 11575590e493
children c14776d25491
comparison
equal deleted inserted replaced
5686:11575590e493 5688:d0a264b803f1
420 target["Metadata"] = metadata; 420 target["Metadata"] = metadata;
421 } 421 }
422 } 422 }
423 423
424 424
425 void ResourceFinder::UpdateRequestLimits()
426 {
427 // TODO-FIND: Check this
428
429 if (lookup_.get() == NULL ||
430 lookup_->HasOnlyMainDicomTags())
431 {
432 isDatabasePaging_ = true;
433
434 if (hasLimits_)
435 {
436 request_.SetLimits(limitsSince_, limitsCount_);
437 }
438 }
439 else if (databaseLimits_ != 0)
440 {
441 // The "+ 1" below is used to test the completeness of the response
442 request_.SetLimits(0, databaseLimits_ + 1);
443 isDatabasePaging_ = false;
444 }
445 else
446 {
447 isDatabasePaging_ = false;
448 }
449 }
450
451
425 ResourceFinder::ResourceFinder(ResourceType level, 452 ResourceFinder::ResourceFinder(ResourceType level,
426 bool expand) : 453 bool expand) :
427 request_(level), 454 request_(level),
455 databaseLimits_(0),
456 isDatabasePaging_(true),
457 hasLimits_(false),
458 limitsSince_(0),
459 limitsCount_(0),
428 expand_(expand), 460 expand_(expand),
429 format_(DicomToJsonFormat_Human), 461 format_(DicomToJsonFormat_Human),
430 allowStorageAccess_(true), 462 allowStorageAccess_(true),
431 hasRequestedTags_(false), 463 hasRequestedTags_(false),
432 includeAllMetadata_(false) 464 includeAllMetadata_(false)
433 { 465 {
466 UpdateRequestLimits();
467
434 if (expand) 468 if (expand)
435 { 469 {
436 request_.SetRetrieveMainDicomTags(true); 470 request_.SetRetrieveMainDicomTags(true);
437 request_.SetRetrieveMetadata(true); 471 request_.SetRetrieveMetadata(true);
438 request_.SetRetrieveLabels(true); 472 request_.SetRetrieveLabels(true);
464 } 498 }
465 } 499 }
466 } 500 }
467 501
468 502
503 void ResourceFinder::SetDatabaseLimits(uint64_t limits)
504 {
505 databaseLimits_ = limits;
506 UpdateRequestLimits();
507 }
508
509
510 void ResourceFinder::SetLimits(uint64_t since,
511 uint64_t count)
512 {
513 if (hasLimits_)
514 {
515 throw OrthancException(ErrorCode_BadSequenceOfCalls);
516 }
517 else
518 {
519 hasLimits_ = true;
520 limitsSince_ = since;
521 limitsCount_ = count;
522 UpdateRequestLimits();
523 }
524 }
525
526
469 void ResourceFinder::SetDatabaseLookup(const DatabaseLookup& lookup) 527 void ResourceFinder::SetDatabaseLookup(const DatabaseLookup& lookup)
470 { 528 {
471 lookup_.reset(lookup.Clone()); 529 lookup_.reset(lookup.Clone());
530 UpdateRequestLimits();
472 531
473 for (size_t i = 0; i < lookup.GetConstraintsCount(); i++) 532 for (size_t i = 0; i < lookup.GetConstraintsCount(); i++)
474 { 533 {
475 DicomTag tag = lookup.GetConstraint(i).GetTag(); 534 DicomTag tag = lookup.GetConstraint(i).GetTag();
476 if (IsComputedTag(tag)) 535 if (IsComputedTag(tag))
746 { 805 {
747 index.ExecuteFind(response, request_); 806 index.ExecuteFind(response, request_);
748 } 807 }
749 808
750 809
751 void ResourceFinder::Execute(Json::Value& target, 810 void ResourceFinder::Execute(IVisitor& visitor,
752 ServerContext& context) const 811 ServerContext& context) const
753 { 812 {
754 FindResponse response; 813 FindResponse response;
755 context.GetIndex().ExecuteFind(response, request_); 814 context.GetIndex().ExecuteFind(response, request_);
756 815
757 target = Json::arrayValue; 816 bool complete;
817 if (isDatabasePaging_)
818 {
819 complete = true;
820 }
821 else
822 {
823 complete = (databaseLimits_ == 0 ||
824 response.GetSize() <= databaseLimits_);
825 }
826
827 if (lookup_.get() != NULL &&
828 !lookup_->HasOnlyMainDicomTags())
829 {
830 LOG(INFO) << "Number of candidate resources after fast DB filtering on main DICOM tags: " << response.GetSize();
831 }
832
833 size_t countResults = 0;
834 size_t skipped = 0;
758 835
759 for (size_t i = 0; i < response.GetSize(); i++) 836 for (size_t i = 0; i < response.GetSize(); i++)
760 { 837 {
761 const FindResponse::Resource& resource = response.GetResourceByIndex(i); 838 const FindResponse::Resource& resource = response.GetResourceByIndex(i);
762 839
796 match = lookup_->IsMatch(tags); 873 match = lookup_->IsMatch(tags);
797 } 874 }
798 875
799 if (match) 876 if (match)
800 { 877 {
801 if (expand_) 878 if (isDatabasePaging_)
879 {
880 visitor.Apply(resource, hasRequestedTags_, requestedTags);
881 }
882 else
883 {
884 if (hasLimits_ &&
885 skipped < limitsSince_)
886 {
887 skipped++;
888 }
889 else if (hasLimits_ &&
890 countResults >= limitsCount_)
891 {
892 // Too many results, don't mark as complete
893 complete = false;
894 break;
895 }
896 else
897 {
898 visitor.Apply(resource, hasRequestedTags_, requestedTags);
899 countResults++;
900 }
901 }
902 }
903 }
904
905 if (complete)
906 {
907 visitor.MarkAsComplete();
908 }
909 }
910
911
912 void ResourceFinder::Execute(Json::Value& target,
913 ServerContext& context) const
914 {
915 class Visitor : public IVisitor
916 {
917 private:
918 const ResourceFinder& that_;
919 ServerIndex& index_;
920 Json::Value& target_;
921
922 public:
923 Visitor(const ResourceFinder& that,
924 ServerIndex& index,
925 Json::Value& target) :
926 that_(that),
927 index_(index),
928 target_(target)
929 {
930 }
931
932 virtual void Apply(const FindResponse::Resource& resource,
933 bool hasRequestedTags,
934 const DicomMap& requestedTags) ORTHANC_OVERRIDE
935 {
936 if (that_.expand_)
802 { 937 {
803 Json::Value item; 938 Json::Value item;
804 Expand(item, resource, context.GetIndex()); 939 that_.Expand(item, resource, index_);
805 940
806 if (hasRequestedTags_) 941 if (hasRequestedTags)
807 { 942 {
808 static const char* const REQUESTED_TAGS = "RequestedTags"; 943 static const char* const REQUESTED_TAGS = "RequestedTags";
809 item[REQUESTED_TAGS] = Json::objectValue; 944 item[REQUESTED_TAGS] = Json::objectValue;
810 FromDcmtkBridge::ToJson(item[REQUESTED_TAGS], requestedTags, format_); 945 FromDcmtkBridge::ToJson(item[REQUESTED_TAGS], requestedTags, that_.format_);
811 } 946 }
812 947
813 target.append(item); 948 target_.append(item);
814 } 949 }
815 else 950 else
816 { 951 {
817 target.append(resource.GetIdentifier()); 952 target_.append(resource.GetIdentifier());
818 } 953 }
819 } 954 }
820 } 955
956 virtual void MarkAsComplete() ORTHANC_OVERRIDE
957 {
958 }
959 };
960
961 target = Json::arrayValue;
962
963 Visitor visitor(*this, context.GetIndex(), target);
964 Execute(visitor, context);
821 } 965 }
822 966
823 967
824 bool ResourceFinder::ExecuteOneResource(Json::Value& target, 968 bool ResourceFinder::ExecuteOneResource(Json::Value& target,
825 ServerContext& context) const 969 ServerContext& context) const