Mercurial > hg > orthanc
comparison OrthancServer/OrthancRestApi/OrthancRestArchive.cpp @ 1777:0f5c416969dc
more memory-efficient ArchiveIndex
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 13 Nov 2015 11:51:19 +0100 |
parents | 3c28f5f6c9b7 |
children | 776573e592da |
comparison
equal
deleted
inserted
replaced
1776:3c28f5f6c9b7 | 1777:0f5c416969dc |
---|---|
510 id_(id), dicom_(dicom) | 510 id_(id), dicom_(dicom) |
511 { | 511 { |
512 } | 512 } |
513 }; | 513 }; |
514 | 514 |
515 // A "NULL" value for ArchiveIndex indicates a non-expanded node | |
515 typedef std::map<std::string, ArchiveIndex*> Resources; | 516 typedef std::map<std::string, ArchiveIndex*> Resources; |
516 | 517 |
517 ServerIndex& index_; | 518 ResourceType level_; |
518 ResourceType level_; | 519 Resources resources_; // Only at patient/study/series level |
519 Resources resources_; | 520 std::list<Instance> instances_; // Only at instance level |
520 std::vector<Instance> instances_; | 521 |
521 | 522 |
522 void AddResourceToExpand(const std::string& id) | 523 void AddResourceToExpand(ServerIndex& index, |
523 { | 524 const std::string& id) |
524 resources_[id] = NULL; | 525 { |
525 } | 526 if (level_ == ResourceType_Instance) |
527 { | |
528 FileInfo tmp; | |
529 if (index.LookupAttachment(tmp, id, FileContentType_Dicom)) | |
530 { | |
531 instances_.push_back(Instance(id, tmp)); | |
532 } | |
533 } | |
534 else | |
535 { | |
536 resources_[id] = NULL; | |
537 } | |
538 } | |
539 | |
526 | 540 |
527 public: | 541 public: |
528 ArchiveIndex(ServerIndex& index, | 542 ArchiveIndex(ResourceType level) : |
529 ResourceType level) : | |
530 index_(index), | |
531 level_(level) | 543 level_(level) |
532 { | 544 { |
533 } | 545 } |
534 | 546 |
535 ~ArchiveIndex() | 547 ~ArchiveIndex() |
539 { | 551 { |
540 delete it->second; | 552 delete it->second; |
541 } | 553 } |
542 } | 554 } |
543 | 555 |
544 void Add(const ResourceIdentifiers& resource) | 556 |
557 void Add(ServerIndex& index, | |
558 const ResourceIdentifiers& resource) | |
545 { | 559 { |
546 const std::string& id = resource.GetIdentifier(level_); | 560 const std::string& id = resource.GetIdentifier(level_); |
547 Resources::iterator previous = resources_.find(id); | 561 Resources::iterator previous = resources_.find(id); |
548 | 562 |
549 if (resource.GetLevel() == level_) | 563 if (level_ == ResourceType_Instance) |
564 { | |
565 AddResourceToExpand(index, id); | |
566 } | |
567 else if (resource.GetLevel() == level_) | |
550 { | 568 { |
551 // Mark this resource for further expansion | 569 // Mark this resource for further expansion |
552 if (previous != resources_.end()) | 570 if (previous != resources_.end()) |
553 { | 571 { |
554 delete previous->second; | 572 delete previous->second; |
557 resources_[id] = NULL; | 575 resources_[id] = NULL; |
558 } | 576 } |
559 else if (previous == resources_.end()) | 577 else if (previous == resources_.end()) |
560 { | 578 { |
561 // This is the first time we meet this resource | 579 // This is the first time we meet this resource |
562 std::auto_ptr<ArchiveIndex> child(new ArchiveIndex(index_, GetChildResourceType(level_))); | 580 std::auto_ptr<ArchiveIndex> child(new ArchiveIndex(GetChildResourceType(level_))); |
563 child->Add(resource); | 581 child->Add(index, resource); |
564 resources_[id] = child.release(); | 582 resources_[id] = child.release(); |
565 } | 583 } |
566 else if (previous->second != NULL) | 584 else if (previous->second != NULL) |
567 { | 585 { |
568 previous->second->Add(resource); | 586 previous->second->Add(index, resource); |
569 } | 587 } |
570 else | 588 else |
571 { | 589 { |
572 // Nothing to do: This item is marked for further expansion | 590 // Nothing to do: This item is marked for further expansion |
573 } | 591 } |
574 } | 592 } |
575 | 593 |
576 | 594 |
577 void Expand() | 595 void Expand(ServerIndex& index) |
578 { | 596 { |
579 if (level_ == ResourceType_Instance) | 597 if (level_ == ResourceType_Instance) |
580 { | 598 { |
581 // At the instance level, locate all the DICOM files | 599 // Expanding an instance node makes no sense |
582 // associated with the instances | 600 return; |
583 instances_.reserve(resources_.size()); | 601 } |
584 | 602 |
585 for (Resources::iterator it = resources_.begin(); | 603 for (Resources::iterator it = resources_.begin(); |
586 it != resources_.end(); ++it) | 604 it != resources_.end(); ++it) |
587 { | 605 { |
588 assert(it->second == NULL); | 606 if (it->second == NULL) |
589 | 607 { |
590 FileInfo tmp; | 608 // This is resource is marked for expansion |
591 if (index_.LookupAttachment(tmp, it->first, FileContentType_Dicom)) | 609 std::list<std::string> children; |
610 index.GetChildren(children, it->first); | |
611 | |
612 std::auto_ptr<ArchiveIndex> child(new ArchiveIndex(GetChildResourceType(level_))); | |
613 | |
614 for (std::list<std::string>::const_iterator | |
615 it2 = children.begin(); it2 != children.end(); ++it2) | |
592 { | 616 { |
593 instances_.push_back(Instance(it->first, tmp)); | 617 child->AddResourceToExpand(index, *it2); |
594 } | 618 } |
595 } | 619 |
596 } | 620 it->second = child.release(); |
597 else | 621 } |
598 { | 622 |
599 // At the patient, study or series level | 623 assert(it->second != NULL); |
600 for (Resources::iterator it = resources_.begin(); | 624 it->second->Expand(index); |
601 it != resources_.end(); ++it) | 625 } |
602 { | |
603 if (it->second == NULL) | |
604 { | |
605 // This is resource is marked for expansion | |
606 std::list<std::string> children; | |
607 index_.GetChildren(children, it->first); | |
608 | |
609 std::auto_ptr<ArchiveIndex> child(new ArchiveIndex(index_, GetChildResourceType(level_))); | |
610 | |
611 for (std::list<std::string>::const_iterator | |
612 it2 = children.begin(); it2 != children.end(); ++it2) | |
613 { | |
614 child->AddResourceToExpand(*it2); | |
615 } | |
616 | |
617 it->second = child.release(); | |
618 } | |
619 | |
620 assert(it->second != NULL); | |
621 it->second->Expand(); | |
622 } | |
623 } | |
624 } | 626 } |
625 | 627 |
626 | 628 |
627 void Apply(IArchiveVisitor& visitor) const | 629 void Apply(IArchiveVisitor& visitor) const |
628 { | 630 { |
629 if (level_ == ResourceType_Instance) | 631 if (level_ == ResourceType_Instance) |
630 { | 632 { |
631 for (size_t i = 0; i < instances_.size(); i++) | 633 for (std::list<Instance>::const_iterator |
632 { | 634 it = instances_.begin(); it != instances_.end(); ++it) |
633 visitor.AddInstance(instances_[i].id_, instances_[i].dicom_); | 635 { |
636 visitor.AddInstance(it->id_, it->dicom_); | |
634 } | 637 } |
635 } | 638 } |
636 else | 639 else |
637 { | 640 { |
638 for (Resources::const_iterator it = resources_.begin(); | 641 for (Resources::const_iterator it = resources_.begin(); |
732 | 735 |
733 Json::Value resources; | 736 Json::Value resources; |
734 if (call.ParseJsonRequest(resources) && | 737 if (call.ParseJsonRequest(resources) && |
735 resources.type() == Json::arrayValue) | 738 resources.type() == Json::arrayValue) |
736 { | 739 { |
737 ArchiveIndex archive(index, ResourceType_Patient); // root | 740 ArchiveIndex archive(ResourceType_Patient); // root |
738 | 741 |
739 for (Json::Value::ArrayIndex i = 0; i < resources.size(); i++) | 742 for (Json::Value::ArrayIndex i = 0; i < resources.size(); i++) |
740 { | 743 { |
741 if (resources[i].type() != Json::stringValue) | 744 if (resources[i].type() != Json::stringValue) |
742 { | 745 { |
743 return; // Bad request | 746 return; // Bad request |
744 } | 747 } |
745 | 748 |
746 ResourceIdentifiers resource(index, resources[i].asString()); | 749 ResourceIdentifiers resource(index, resources[i].asString()); |
747 archive.Add(resource); | 750 archive.Add(index, resource); |
748 } | 751 } |
749 | 752 |
750 archive.Expand(); | 753 archive.Expand(index); |
751 | 754 |
752 PrintVisitor v(std::cout); | 755 PrintVisitor v(std::cout); |
753 archive.Apply(v); | 756 archive.Apply(v); |
754 | 757 |
755 StatisticsVisitor s; | 758 StatisticsVisitor s; |