comparison OrthancServer/ServerIndex.cpp @ 3080:1a75595d8e44 db-changes

started refactoring of ServerIndex::Store()
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 03 Jan 2019 18:21:22 +0100
parents ead8576a02ef
children 847a0ed92654
comparison
equal deleted inserted replaced
3079:65e2bfa953ef 3080:1a75595d8e44
610 } 610 }
611 } 611 }
612 612
613 613
614 614
615 int64_t ServerIndex::CreateResource(const std::string& publicId,
616 ResourceType type)
617 {
618 int64_t id = db_.CreateResource(publicId, type);
619
620 ChangeType changeType;
621 switch (type)
622 {
623 case ResourceType_Patient:
624 changeType = ChangeType_NewPatient;
625 break;
626
627 case ResourceType_Study:
628 changeType = ChangeType_NewStudy;
629 break;
630
631 case ResourceType_Series:
632 changeType = ChangeType_NewSeries;
633 break;
634
635 case ResourceType_Instance:
636 changeType = ChangeType_NewInstance;
637 break;
638
639 default:
640 throw OrthancException(ErrorCode_InternalError);
641 }
642
643 ServerIndexChange change(changeType, type, publicId);
644 db_.LogChange(id, change);
645
646 assert(listener_.get() != NULL);
647 listener_->SignalChange(change);
648
649 return id;
650 }
651
652
653 ServerIndex::ServerIndex(ServerContext& context, 615 ServerIndex::ServerIndex(ServerContext& context,
654 IDatabaseWrapper& db, 616 IDatabaseWrapper& db,
655 unsigned int threadSleep) : 617 unsigned int threadSleep) :
656 done_(false), 618 done_(false),
657 db_(db), 619 db_(db),
718 db_.SetMetadata(instance, metadata, value); 680 db_.SetMetadata(instance, metadata, value);
719 instanceMetadata[metadata] = value; 681 instanceMetadata[metadata] = value;
720 } 682 }
721 683
722 684
723 685 void ServerIndex::SignalNewResource(ChangeType changeType,
686 ResourceType level,
687 const std::string& publicId,
688 int64_t internalId)
689 {
690 ServerIndexChange change(changeType, level, publicId);
691 db_.LogChange(internalId, change);
692
693 assert(listener_.get() != NULL);
694 listener_->SignalChange(change);
695 }
696
697
724 StoreStatus ServerIndex::Store(std::map<MetadataType, std::string>& instanceMetadata, 698 StoreStatus ServerIndex::Store(std::map<MetadataType, std::string>& instanceMetadata,
725 DicomInstanceToStore& instanceToStore, 699 DicomInstanceToStore& instanceToStore,
726 const Attachments& attachments) 700 const Attachments& attachments)
727 { 701 {
728 boost::mutex::scoped_lock lock(mutex_); 702 boost::mutex::scoped_lock lock(mutex_);
730 const DicomMap& dicomSummary = instanceToStore.GetSummary(); 704 const DicomMap& dicomSummary = instanceToStore.GetSummary();
731 const ServerIndex::MetadataMap& metadata = instanceToStore.GetMetadata(); 705 const ServerIndex::MetadataMap& metadata = instanceToStore.GetMetadata();
732 706
733 instanceMetadata.clear(); 707 instanceMetadata.clear();
734 708
709 const std::string hashPatient = instanceToStore.GetHasher().HashPatient();
710 const std::string hashStudy = instanceToStore.GetHasher().HashStudy();
711 const std::string hashSeries = instanceToStore.GetHasher().HashSeries();
712 const std::string hashInstance = instanceToStore.GetHasher().HashInstance();
713
735 try 714 try
736 { 715 {
737 Transaction t(*this); 716 Transaction t(*this);
738 717
718 IDatabaseWrapper::CreateInstanceResult status;
719 int64_t instanceId;
720
739 // Check whether this instance is already stored 721 // Check whether this instance is already stored
740 { 722 if (!db_.CreateInstance(status, instanceId, hashPatient,
741 ResourceType type; 723 hashStudy, hashSeries, hashInstance, overwrite_))
742 int64_t tmp; 724 {
743 if (db_.LookupResource(tmp, type, instanceToStore.GetHasher().HashInstance())) 725 // Do nothing if the instance already exists and overwriting is disabled
744 { 726 db_.GetAllMetadata(instanceMetadata, instanceId);
745 assert(type == ResourceType_Instance); 727 return StoreStatus_AlreadyStored;
746 728 }
747 if (overwrite_) 729
748 { 730
749 // Overwrite the old instance 731 // Warn about the creation of new resources. The order must be from instance to patient.
750 LOG(INFO) << "Overwriting instance: " << instanceToStore.GetHasher().HashInstance(); 732 SignalNewResource(ChangeType_NewInstance, ResourceType_Instance, hashInstance, instanceId);
751 db_.DeleteResource(tmp); 733
752 } 734 if (status.isNewSeries_)
753 else 735 {
754 { 736 SignalNewResource(ChangeType_NewSeries, ResourceType_Series, hashSeries, status.seriesId_);
755 // Do nothing if the instance already exists 737 }
756 db_.GetAllMetadata(instanceMetadata, tmp); 738
757 return StoreStatus_AlreadyStored; 739 if (status.isNewStudy_)
758 } 740 {
759 } 741 SignalNewResource(ChangeType_NewStudy, ResourceType_Study, hashStudy, status.studyId_);
760 } 742 }
761 743
744 if (status.isNewPatient_)
745 {
746 SignalNewResource(ChangeType_NewPatient, ResourceType_Patient, hashPatient, status.patientId_);
747 }
748
749
762 // Ensure there is enough room in the storage for the new instance 750 // Ensure there is enough room in the storage for the new instance
763 uint64_t instanceSize = 0; 751 uint64_t instanceSize = 0;
764 for (Attachments::const_iterator it = attachments.begin(); 752 for (Attachments::const_iterator it = attachments.begin();
765 it != attachments.end(); ++it) 753 it != attachments.end(); ++it)
766 { 754 {
767 instanceSize += it->GetCompressedSize(); 755 instanceSize += it->GetCompressedSize();
768 } 756 }
769 757
770 Recycle(instanceSize, instanceToStore.GetHasher().HashPatient()); 758 Recycle(instanceSize, hashPatient /* don't consider the current patient for recycling */);
771 759
772 // Create the instance 760
773 int64_t instance = CreateResource(instanceToStore.GetHasher().HashInstance(), ResourceType_Instance); 761 // Populate the newly-created resources
774 ServerToolbox::StoreMainDicomTags(db_, instance, ResourceType_Instance, dicomSummary); 762 // TODO - GROUP THIS
775 763
776 // Detect up to which level the patient/study/series/instance 764 ServerToolbox::StoreMainDicomTags(db_, instanceId, ResourceType_Instance, dicomSummary);
777 // hierarchy must be created 765
778 int64_t patient = -1, study = -1, series = -1; 766 if (status.isNewSeries_)
779 bool isNewPatient = false; 767 {
780 bool isNewStudy = false; 768 ServerToolbox::StoreMainDicomTags(db_, status.seriesId_, ResourceType_Series, dicomSummary);
781 bool isNewSeries = false; 769 }
782 770
783 { 771 if (status.isNewStudy_)
784 ResourceType dummy; 772 {
785 773 ServerToolbox::StoreMainDicomTags(db_, status.studyId_, ResourceType_Study, dicomSummary);
786 if (db_.LookupResource(series, dummy, instanceToStore.GetHasher().HashSeries())) 774 }
787 { 775
788 assert(dummy == ResourceType_Series); 776 if (status.isNewPatient_)
789 // The patient, the study and the series already exist 777 {
790 778 ServerToolbox::StoreMainDicomTags(db_, status.patientId_, ResourceType_Patient, dicomSummary);
791 bool ok = (db_.LookupResource(patient, dummy, instanceToStore.GetHasher().HashPatient()) && 779 }
792 db_.LookupResource(study, dummy, instanceToStore.GetHasher().HashStudy())); 780
793 assert(ok); 781
794 }
795 else if (db_.LookupResource(study, dummy, instanceToStore.GetHasher().HashStudy()))
796 {
797 assert(dummy == ResourceType_Study);
798
799 // New series: The patient and the study already exist
800 isNewSeries = true;
801
802 bool ok = db_.LookupResource(patient, dummy, instanceToStore.GetHasher().HashPatient());
803 assert(ok);
804 }
805 else if (db_.LookupResource(patient, dummy, instanceToStore.GetHasher().HashPatient()))
806 {
807 assert(dummy == ResourceType_Patient);
808
809 // New study and series: The patient already exist
810 isNewStudy = true;
811 isNewSeries = true;
812 }
813 else
814 {
815 // New patient, study and series: Nothing exists
816 isNewPatient = true;
817 isNewStudy = true;
818 isNewSeries = true;
819 }
820 }
821
822 // Create the series if needed
823 if (isNewSeries)
824 {
825 series = CreateResource(instanceToStore.GetHasher().HashSeries(), ResourceType_Series);
826 ServerToolbox::StoreMainDicomTags(db_, series, ResourceType_Series, dicomSummary);
827 }
828
829 // Create the study if needed
830 if (isNewStudy)
831 {
832 study = CreateResource(instanceToStore.GetHasher().HashStudy(), ResourceType_Study);
833 ServerToolbox::StoreMainDicomTags(db_, study, ResourceType_Study, dicomSummary);
834 }
835
836 // Create the patient if needed
837 if (isNewPatient)
838 {
839 patient = CreateResource(instanceToStore.GetHasher().HashPatient(), ResourceType_Patient);
840 ServerToolbox::StoreMainDicomTags(db_, patient, ResourceType_Patient, dicomSummary);
841 }
842
843 // Create the parent-to-child links
844 db_.AttachChild(series, instance);
845
846 if (isNewSeries)
847 {
848 db_.AttachChild(study, series);
849 }
850
851 if (isNewStudy)
852 {
853 db_.AttachChild(patient, study);
854 }
855
856 // Sanity checks
857 assert(patient != -1);
858 assert(study != -1);
859 assert(series != -1);
860 assert(instance != -1);
861
862 // Attach the files to the newly created instance 782 // Attach the files to the newly created instance
863 for (Attachments::const_iterator it = attachments.begin(); 783 for (Attachments::const_iterator it = attachments.begin();
864 it != attachments.end(); ++it) 784 it != attachments.end(); ++it)
865 { 785 {
866 db_.AddAttachment(instance, *it); 786 db_.AddAttachment(instanceId, *it);
867 } 787 }
788
868 789
869 // Attach the user-specified metadata 790 // Attach the user-specified metadata
791 // TODO - GROUP THIS
870 for (MetadataMap::const_iterator 792 for (MetadataMap::const_iterator
871 it = metadata.begin(); it != metadata.end(); ++it) 793 it = metadata.begin(); it != metadata.end(); ++it)
872 { 794 {
873 switch (it->first.first) 795 switch (it->first.first)
874 { 796 {
875 case ResourceType_Patient: 797 case ResourceType_Patient:
876 db_.SetMetadata(patient, it->first.second, it->second); 798 db_.SetMetadata(status.patientId_, it->first.second, it->second);
877 break; 799 break;
878 800
879 case ResourceType_Study: 801 case ResourceType_Study:
880 db_.SetMetadata(study, it->first.second, it->second); 802 db_.SetMetadata(status.studyId_, it->first.second, it->second);
881 break; 803 break;
882 804
883 case ResourceType_Series: 805 case ResourceType_Series:
884 db_.SetMetadata(series, it->first.second, it->second); 806 db_.SetMetadata(status.seriesId_, it->first.second, it->second);
885 break; 807 break;
886 808
887 case ResourceType_Instance: 809 case ResourceType_Instance:
888 SetInstanceMetadata(instanceMetadata, instance, it->first.second, it->second); 810 SetInstanceMetadata(instanceMetadata, instanceId, it->first.second, it->second);
889 break; 811 break;
890 812
891 default: 813 default:
892 throw OrthancException(ErrorCode_ParameterOutOfRange); 814 throw OrthancException(ErrorCode_ParameterOutOfRange);
893 } 815 }
894 } 816 }
895 817
896 // Attach the auto-computed metadata for the patient/study/series levels 818 // Attach the auto-computed metadata for the patient/study/series levels
897 std::string now = SystemToolbox::GetNowIsoString(true /* use UTC time (not local time) */); 819 std::string now = SystemToolbox::GetNowIsoString(true /* use UTC time (not local time) */);
898 db_.SetMetadata(series, MetadataType_LastUpdate, now); 820 db_.SetMetadata(status.seriesId_, MetadataType_LastUpdate, now);
899 db_.SetMetadata(study, MetadataType_LastUpdate, now); 821 db_.SetMetadata(status.studyId_, MetadataType_LastUpdate, now);
900 db_.SetMetadata(patient, MetadataType_LastUpdate, now); 822 db_.SetMetadata(status.patientId_, MetadataType_LastUpdate, now);
901 823
902 // Attach the auto-computed metadata for the instance level, 824 // Attach the auto-computed metadata for the instance level,
903 // reflecting these additions into the input metadata map 825 // reflecting these additions into the input metadata map
904 SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_ReceptionDate, now); 826 SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_ReceptionDate, now);
905 SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_RemoteAet, 827 SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_RemoteAet,
906 instanceToStore.GetOrigin().GetRemoteAetC()); 828 instanceToStore.GetOrigin().GetRemoteAetC());
907 SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_Origin, 829 SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_Origin,
908 EnumerationToString(instanceToStore.GetOrigin().GetRequestOrigin())); 830 EnumerationToString(instanceToStore.GetOrigin().GetRequestOrigin()));
909 831
910 { 832 {
911 std::string s; 833 std::string s;
912 834
913 if (instanceToStore.LookupTransferSyntax(s)) 835 if (instanceToStore.LookupTransferSyntax(s))
914 { 836 {
915 // New in Orthanc 1.2.0 837 // New in Orthanc 1.2.0
916 SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_TransferSyntax, s); 838 SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_TransferSyntax, s);
917 } 839 }
918 840
919 if (instanceToStore.GetOrigin().LookupRemoteIp(s)) 841 if (instanceToStore.GetOrigin().LookupRemoteIp(s))
920 { 842 {
921 // New in Orthanc 1.4.0 843 // New in Orthanc 1.4.0
922 SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_RemoteIp, s); 844 SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_RemoteIp, s);
923 } 845 }
924 846
925 if (instanceToStore.GetOrigin().LookupCalledAet(s)) 847 if (instanceToStore.GetOrigin().LookupCalledAet(s))
926 { 848 {
927 // New in Orthanc 1.4.0 849 // New in Orthanc 1.4.0
928 SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_CalledAet, s); 850 SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_CalledAet, s);
929 } 851 }
930 852
931 if (instanceToStore.GetOrigin().LookupHttpUsername(s)) 853 if (instanceToStore.GetOrigin().LookupHttpUsername(s))
932 { 854 {
933 // New in Orthanc 1.4.0 855 // New in Orthanc 1.4.0
934 SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_HttpUsername, s); 856 SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_HttpUsername, s);
935 } 857 }
936 } 858 }
937 859
938 const DicomValue* value; 860 const DicomValue* value;
939 if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_SOP_CLASS_UID)) != NULL && 861 if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_SOP_CLASS_UID)) != NULL &&
940 !value->IsNull() && 862 !value->IsNull() &&
941 !value->IsBinary()) 863 !value->IsBinary())
942 { 864 {
943 SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_SopClassUid, value->GetContent()); 865 SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_SopClassUid, value->GetContent());
944 } 866 }
945 867
946 if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_INSTANCE_NUMBER)) != NULL || 868 if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_INSTANCE_NUMBER)) != NULL ||
947 (value = dicomSummary.TestAndGetValue(DICOM_TAG_IMAGE_INDEX)) != NULL) 869 (value = dicomSummary.TestAndGetValue(DICOM_TAG_IMAGE_INDEX)) != NULL)
948 { 870 {
949 if (!value->IsNull() && 871 if (!value->IsNull() &&
950 !value->IsBinary()) 872 !value->IsBinary())
951 { 873 {
952 SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_IndexInSeries, value->GetContent()); 874 SetInstanceMetadata(instanceMetadata, instanceId, MetadataType_Instance_IndexInSeries, value->GetContent());
953 } 875 }
954 } 876 }
955 877
956 // Check whether the series of this new instance is now completed 878 // Check whether the series of this new instance is now completed
957 if (isNewSeries) 879 if (status.isNewSeries_)
958 { 880 {
959 ComputeExpectedNumberOfInstances(db_, series, dicomSummary); 881 ComputeExpectedNumberOfInstances(db_, status.seriesId_, dicomSummary);
960 } 882 }
961 883
962 SeriesStatus seriesStatus = GetSeriesStatus(series); 884 SeriesStatus seriesStatus = GetSeriesStatus(status.seriesId_);
963 if (seriesStatus == SeriesStatus_Complete) 885 if (seriesStatus == SeriesStatus_Complete)
964 { 886 {
965 LogChange(series, ChangeType_CompletedSeries, ResourceType_Series, instanceToStore.GetHasher().HashSeries()); 887 LogChange(status.seriesId_, ChangeType_CompletedSeries, ResourceType_Series, hashSeries);
966 } 888 }
967 889
968 // Mark the parent resources of this instance as unstable 890 // Mark the parent resources of this instance as unstable
969 MarkAsUnstable(series, ResourceType_Series, instanceToStore.GetHasher().HashSeries()); 891 MarkAsUnstable(status.seriesId_, ResourceType_Series, hashSeries);
970 MarkAsUnstable(study, ResourceType_Study, instanceToStore.GetHasher().HashStudy()); 892 MarkAsUnstable(status.studyId_, ResourceType_Study, hashStudy);
971 MarkAsUnstable(patient, ResourceType_Patient, instanceToStore.GetHasher().HashPatient()); 893 MarkAsUnstable(status.patientId_, ResourceType_Patient, hashPatient);
972 894
973 t.Commit(instanceSize); 895 t.Commit(instanceSize);
974 896
975 return StoreStatus_Success; 897 return StoreStatus_Success;
976 } 898 }