Mercurial > hg > orthanc
comparison OrthancServer/Sources/ServerContext.cpp @ 4627:f7d5372b59b3 db-changes
handling revisions of attachments
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 20 Apr 2021 15:11:59 +0200 |
parents | 95ffe3b6ef7c |
children | 88e892e25a51 |
comparison
equal
deleted
inserted
replaced
4626:686f189a903d | 4627:f7d5372b59b3 |
---|---|
751 void ServerContext::AnswerAttachment(RestApiOutput& output, | 751 void ServerContext::AnswerAttachment(RestApiOutput& output, |
752 const std::string& resourceId, | 752 const std::string& resourceId, |
753 FileContentType content) | 753 FileContentType content) |
754 { | 754 { |
755 FileInfo attachment; | 755 FileInfo attachment; |
756 if (!index_.LookupAttachment(attachment, resourceId, content)) | 756 int64_t revision; |
757 if (!index_.LookupAttachment(attachment, revision, resourceId, content)) | |
757 { | 758 { |
758 throw OrthancException(ErrorCode_UnknownResource); | 759 throw OrthancException(ErrorCode_UnknownResource); |
759 } | 760 } |
760 | 761 else |
761 StorageAccessor accessor(area_, GetMetricsRegistry()); | 762 { |
762 accessor.AnswerFile(output, attachment, GetFileContentMime(content)); | 763 StorageAccessor accessor(area_, GetMetricsRegistry()); |
764 accessor.AnswerFile(output, attachment, GetFileContentMime(content)); | |
765 } | |
763 } | 766 } |
764 | 767 |
765 | 768 |
766 void ServerContext::ChangeAttachmentCompression(const std::string& resourceId, | 769 void ServerContext::ChangeAttachmentCompression(const std::string& resourceId, |
767 FileContentType attachmentType, | 770 FileContentType attachmentType, |
771 << EnumerationToString(attachmentType) | 774 << EnumerationToString(attachmentType) |
772 << " of resource " << resourceId << " to " | 775 << " of resource " << resourceId << " to " |
773 << compression; | 776 << compression; |
774 | 777 |
775 FileInfo attachment; | 778 FileInfo attachment; |
776 if (!index_.LookupAttachment(attachment, resourceId, attachmentType)) | 779 int64_t revision; |
780 if (!index_.LookupAttachment(attachment, revision, resourceId, attachmentType)) | |
777 { | 781 { |
778 throw OrthancException(ErrorCode_UnknownResource); | 782 throw OrthancException(ErrorCode_UnknownResource); |
779 } | 783 } |
780 | 784 |
781 if (attachment.GetCompressionType() == compression) | 785 if (attachment.GetCompressionType() == compression) |
792 FileInfo modified = accessor.Write(content.empty() ? NULL : content.c_str(), | 796 FileInfo modified = accessor.Write(content.empty() ? NULL : content.c_str(), |
793 content.size(), attachmentType, compression, storeMD5_); | 797 content.size(), attachmentType, compression, storeMD5_); |
794 | 798 |
795 try | 799 try |
796 { | 800 { |
797 StoreStatus status = index_.AddAttachment(modified, resourceId); | 801 int64_t newRevision; // ignored |
802 StoreStatus status = index_.AddAttachment(newRevision, modified, resourceId, true, revision); | |
798 if (status != StoreStatus_Success) | 803 if (status != StoreStatus_Success) |
799 { | 804 { |
800 accessor.Remove(modified); | 805 accessor.Remove(modified); |
801 throw OrthancException(ErrorCode_Database); | 806 throw OrthancException(ErrorCode_Database); |
802 } | 807 } |
831 * area does not support range reads, or it "StorageCompression" | 836 * area does not support range reads, or it "StorageCompression" |
832 * is enabled). Simply return this attachment. | 837 * is enabled). Simply return this attachment. |
833 **/ | 838 **/ |
834 | 839 |
835 FileInfo attachment; | 840 FileInfo attachment; |
836 | 841 int64_t revision; |
837 if (index_.LookupAttachment(attachment, instancePublicId, FileContentType_DicomUntilPixelData)) | 842 |
843 if (index_.LookupAttachment(attachment, revision, instancePublicId, FileContentType_DicomUntilPixelData)) | |
838 { | 844 { |
839 std::string dicom; | 845 std::string dicom; |
840 | 846 |
841 { | 847 { |
842 StorageAccessor accessor(area_, GetMetricsRegistry()); | 848 StorageAccessor accessor(area_, GetMetricsRegistry()); |
891 } | 897 } |
892 | 898 |
893 | 899 |
894 if (hasPixelDataOffset && | 900 if (hasPixelDataOffset && |
895 area_.HasReadRange() && | 901 area_.HasReadRange() && |
896 index_.LookupAttachment(attachment, instancePublicId, FileContentType_Dicom) && | 902 index_.LookupAttachment(attachment, revision, instancePublicId, FileContentType_Dicom) && |
897 attachment.GetCompressionType() == CompressionType_None) | 903 attachment.GetCompressionType() == CompressionType_None) |
898 { | 904 { |
899 /** | 905 /** |
900 * CASE 2: The pixel data offset is known, AND that a range read | 906 * CASE 2: The pixel data offset is known, AND that a range read |
901 * can be used to retrieve the truncated DICOM file. Note that | 907 * can be used to retrieve the truncated DICOM file. Note that |
920 OrthancConfiguration::DefaultDicomDatasetToJson(result, parsed, ignoreTagLength); | 926 OrthancConfiguration::DefaultDicomDatasetToJson(result, parsed, ignoreTagLength); |
921 InjectEmptyPixelData(result); | 927 InjectEmptyPixelData(result); |
922 } | 928 } |
923 } | 929 } |
924 else if (ignoreTagLength.empty() && | 930 else if (ignoreTagLength.empty() && |
925 index_.LookupAttachment(attachment, instancePublicId, FileContentType_DicomAsJson)) | 931 index_.LookupAttachment(attachment, revision, instancePublicId, FileContentType_DicomAsJson)) |
926 { | 932 { |
927 /** | 933 /** |
928 * CASE 3: This instance was created using Orthanc <= | 934 * CASE 3: This instance was created using Orthanc <= |
929 * 1.9.0. Reuse the old "DICOM-as-JSON" attachment if available. | 935 * 1.9.0. Reuse the old "DICOM-as-JSON" attachment if available. |
930 * This is for backward compatibility: A call to | 936 * This is for backward compatibility: A call to |
976 boost::lexical_cast<std::string>(pixelDataOffset)); | 982 boost::lexical_cast<std::string>(pixelDataOffset)); |
977 | 983 |
978 if (!area_.HasReadRange() || | 984 if (!area_.HasReadRange() || |
979 compressionEnabled_) | 985 compressionEnabled_) |
980 { | 986 { |
981 AddAttachment(instancePublicId, FileContentType_DicomUntilPixelData, | 987 int64_t newRevision; |
982 dicom.empty() ? NULL: dicom.c_str(), pixelDataOffset); | 988 AddAttachment(newRevision, instancePublicId, FileContentType_DicomUntilPixelData, |
989 dicom.empty() ? NULL: dicom.c_str(), pixelDataOffset, | |
990 false /* no old revision */, -1 /* dummy revision */); | |
983 } | 991 } |
984 } | 992 } |
985 } | 993 } |
986 } | 994 } |
987 } | 995 } |
997 | 1005 |
998 | 1006 |
999 void ServerContext::ReadDicom(std::string& dicom, | 1007 void ServerContext::ReadDicom(std::string& dicom, |
1000 const std::string& instancePublicId) | 1008 const std::string& instancePublicId) |
1001 { | 1009 { |
1002 ReadAttachment(dicom, instancePublicId, FileContentType_Dicom, true /* uncompress */); | 1010 int64_t revision; |
1011 ReadAttachment(dicom, revision, instancePublicId, FileContentType_Dicom, true /* uncompress */); | |
1003 } | 1012 } |
1004 | 1013 |
1005 | 1014 |
1006 bool ServerContext::ReadDicomUntilPixelData(std::string& dicom, | 1015 bool ServerContext::ReadDicomUntilPixelData(std::string& dicom, |
1007 const std::string& instancePublicId) | 1016 const std::string& instancePublicId) |
1010 { | 1019 { |
1011 return false; | 1020 return false; |
1012 } | 1021 } |
1013 | 1022 |
1014 FileInfo attachment; | 1023 FileInfo attachment; |
1015 if (!index_.LookupAttachment(attachment, instancePublicId, FileContentType_Dicom)) | 1024 int64_t revision; // Ignored |
1025 if (!index_.LookupAttachment(attachment, revision, instancePublicId, FileContentType_Dicom)) | |
1016 { | 1026 { |
1017 throw OrthancException(ErrorCode_InternalError, | 1027 throw OrthancException(ErrorCode_InternalError, |
1018 "Unable to read the DICOM file of instance " + instancePublicId); | 1028 "Unable to read the DICOM file of instance " + instancePublicId); |
1019 } | 1029 } |
1020 | 1030 |
1021 std::string s; | 1031 std::string s; |
1022 int64_t revision; // Ignored | |
1023 | 1032 |
1024 if (attachment.GetCompressionType() == CompressionType_None && | 1033 if (attachment.GetCompressionType() == CompressionType_None && |
1025 index_.LookupMetadata(s, revision, instancePublicId, ResourceType_Instance, | 1034 index_.LookupMetadata(s, revision, instancePublicId, ResourceType_Instance, |
1026 MetadataType_Instance_PixelDataOffset) && | 1035 MetadataType_Instance_PixelDataOffset) && |
1027 !s.empty()) | 1036 !s.empty()) |
1044 return false; | 1053 return false; |
1045 } | 1054 } |
1046 | 1055 |
1047 | 1056 |
1048 void ServerContext::ReadAttachment(std::string& result, | 1057 void ServerContext::ReadAttachment(std::string& result, |
1058 int64_t& revision, | |
1049 const std::string& instancePublicId, | 1059 const std::string& instancePublicId, |
1050 FileContentType content, | 1060 FileContentType content, |
1051 bool uncompressIfNeeded) | 1061 bool uncompressIfNeeded) |
1052 { | 1062 { |
1053 FileInfo attachment; | 1063 FileInfo attachment; |
1054 if (!index_.LookupAttachment(attachment, instancePublicId, content)) | 1064 if (!index_.LookupAttachment(attachment, revision, instancePublicId, content)) |
1055 { | 1065 { |
1056 throw OrthancException(ErrorCode_InternalError, | 1066 throw OrthancException(ErrorCode_InternalError, |
1057 "Unable to read attachment " + EnumerationToString(content) + | 1067 "Unable to read attachment " + EnumerationToString(content) + |
1058 " of instance " + instancePublicId); | 1068 " of instance " + instancePublicId); |
1059 } | 1069 } |
1145 LOG(INFO) << "Storing MD5 for attachments: " << (storeMD5 ? "yes" : "no"); | 1155 LOG(INFO) << "Storing MD5 for attachments: " << (storeMD5 ? "yes" : "no"); |
1146 storeMD5_ = storeMD5; | 1156 storeMD5_ = storeMD5; |
1147 } | 1157 } |
1148 | 1158 |
1149 | 1159 |
1150 bool ServerContext::AddAttachment(const std::string& resourceId, | 1160 bool ServerContext::AddAttachment(int64_t& newRevision, |
1161 const std::string& resourceId, | |
1151 FileContentType attachmentType, | 1162 FileContentType attachmentType, |
1152 const void* data, | 1163 const void* data, |
1153 size_t size) | 1164 size_t size, |
1165 bool hasOldRevision, | |
1166 int64_t oldRevision) | |
1154 { | 1167 { |
1155 LOG(INFO) << "Adding attachment " << EnumerationToString(attachmentType) << " to resource " << resourceId; | 1168 LOG(INFO) << "Adding attachment " << EnumerationToString(attachmentType) << " to resource " << resourceId; |
1156 | 1169 |
1157 // TODO Should we use "gzip" instead? | 1170 // TODO Should we use "gzip" instead? |
1158 CompressionType compression = (compressionEnabled_ ? CompressionType_ZlibWithSize : CompressionType_None); | 1171 CompressionType compression = (compressionEnabled_ ? CompressionType_ZlibWithSize : CompressionType_None); |
1159 | 1172 |
1160 StorageAccessor accessor(area_, GetMetricsRegistry()); | 1173 StorageAccessor accessor(area_, GetMetricsRegistry()); |
1161 FileInfo attachment = accessor.Write(data, size, attachmentType, compression, storeMD5_); | 1174 FileInfo attachment = accessor.Write(data, size, attachmentType, compression, storeMD5_); |
1162 | 1175 |
1163 StoreStatus status = index_.AddAttachment(attachment, resourceId); | 1176 StoreStatus status = index_.AddAttachment(newRevision, attachment, resourceId, hasOldRevision, oldRevision); |
1164 if (status != StoreStatus_Success) | 1177 if (status != StoreStatus_Success) |
1165 { | 1178 { |
1166 accessor.Remove(attachment); | 1179 accessor.Remove(attachment); |
1167 return false; | 1180 return false; |
1168 } | 1181 } |