Mercurial > hg > orthanc
comparison OrthancServer/Sources/Database/StatelessDatabaseOperations.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 | 37357df3dc27 |
comparison
equal
deleted
inserted
replaced
4626:686f189a903d | 4627:f7d5372b59b3 |
---|---|
918 case ResourceType_Instance: | 918 case ResourceType_Instance: |
919 { | 919 { |
920 target["Type"] = "Instance"; | 920 target["Type"] = "Instance"; |
921 | 921 |
922 FileInfo attachment; | 922 FileInfo attachment; |
923 if (!transaction.LookupAttachment(attachment, internalId, FileContentType_Dicom)) | 923 int64_t revision; // ignored |
924 if (!transaction.LookupAttachment(attachment, revision, internalId, FileContentType_Dicom)) | |
924 { | 925 { |
925 throw OrthancException(ErrorCode_InternalError); | 926 throw OrthancException(ErrorCode_InternalError); |
926 } | 927 } |
927 | 928 |
928 target["FileSize"] = static_cast<unsigned int>(attachment.GetUncompressedSize()); | 929 target["FileSize"] = static_cast<unsigned int>(attachment.GetUncompressedSize()); |
1013 operations.Apply(*this, target, publicId, level); | 1014 operations.Apply(*this, target, publicId, level); |
1014 } | 1015 } |
1015 | 1016 |
1016 | 1017 |
1017 bool StatelessDatabaseOperations::LookupAttachment(FileInfo& attachment, | 1018 bool StatelessDatabaseOperations::LookupAttachment(FileInfo& attachment, |
1019 int64_t& revision, | |
1018 const std::string& instancePublicId, | 1020 const std::string& instancePublicId, |
1019 FileContentType contentType) | 1021 FileContentType contentType) |
1020 { | 1022 { |
1021 class Operations : public ReadOnlyOperationsT4<bool&, FileInfo&, const std::string&, FileContentType> | 1023 class Operations : public ReadOnlyOperationsT5<bool&, FileInfo&, int64_t&, const std::string&, FileContentType> |
1022 { | 1024 { |
1023 public: | 1025 public: |
1024 virtual void ApplyTuple(ReadOnlyTransaction& transaction, | 1026 virtual void ApplyTuple(ReadOnlyTransaction& transaction, |
1025 const Tuple& tuple) ORTHANC_OVERRIDE | 1027 const Tuple& tuple) ORTHANC_OVERRIDE |
1026 { | 1028 { |
1027 int64_t internalId; | 1029 int64_t internalId; |
1028 ResourceType type; | 1030 ResourceType type; |
1029 if (!transaction.LookupResource(internalId, type, tuple.get<2>())) | 1031 if (!transaction.LookupResource(internalId, type, tuple.get<3>())) |
1030 { | 1032 { |
1031 throw OrthancException(ErrorCode_UnknownResource); | 1033 throw OrthancException(ErrorCode_UnknownResource); |
1032 } | 1034 } |
1033 else if (transaction.LookupAttachment(tuple.get<1>(), internalId, tuple.get<3>())) | 1035 else if (transaction.LookupAttachment(tuple.get<1>(), tuple.get<2>(), internalId, tuple.get<4>())) |
1034 { | 1036 { |
1035 assert(tuple.get<1>().GetContentType() == tuple.get<3>()); | 1037 assert(tuple.get<1>().GetContentType() == tuple.get<4>()); |
1036 tuple.get<0>() = true; | 1038 tuple.get<0>() = true; |
1037 } | 1039 } |
1038 else | 1040 else |
1039 { | 1041 { |
1040 tuple.get<0>() = false; | 1042 tuple.get<0>() = false; |
1042 } | 1044 } |
1043 }; | 1045 }; |
1044 | 1046 |
1045 bool found; | 1047 bool found; |
1046 Operations operations; | 1048 Operations operations; |
1047 operations.Apply(*this, found, attachment, instancePublicId, contentType); | 1049 operations.Apply(*this, found, attachment, revision, instancePublicId, contentType); |
1048 return found; | 1050 return found; |
1049 } | 1051 } |
1050 | 1052 |
1051 | 1053 |
1052 void StatelessDatabaseOperations::GetAllUuids(std::list<std::string>& target, | 1054 void StatelessDatabaseOperations::GetAllUuids(std::list<std::string>& target, |
1545 | 1547 |
1546 for (std::set<FileContentType>::const_iterator | 1548 for (std::set<FileContentType>::const_iterator |
1547 it = f.begin(); it != f.end(); ++it) | 1549 it = f.begin(); it != f.end(); ++it) |
1548 { | 1550 { |
1549 FileInfo attachment; | 1551 FileInfo attachment; |
1550 if (transaction.LookupAttachment(attachment, resource, *it)) | 1552 int64_t revision; // ignored |
1553 if (transaction.LookupAttachment(attachment, revision, resource, *it)) | |
1551 { | 1554 { |
1552 if (attachment.GetContentType() == FileContentType_Dicom) | 1555 if (attachment.GetContentType() == FileContentType_Dicom) |
1553 { | 1556 { |
1554 dicomDiskSize_ += attachment.GetCompressedSize(); | 1557 dicomDiskSize_ += attachment.GetCompressedSize(); |
1555 dicomUncompressedSize_ += attachment.GetUncompressedSize(); | 1558 dicomUncompressedSize_ += attachment.GetUncompressedSize(); |
2242 { | 2245 { |
2243 throw OrthancException(ErrorCode_Revision); | 2246 throw OrthancException(ErrorCode_Revision); |
2244 } | 2247 } |
2245 else | 2248 else |
2246 { | 2249 { |
2247 newRevision_ = oldRevision_ + 1; | 2250 newRevision_ = expectedRevision + 1; |
2248 } | 2251 } |
2249 } | 2252 } |
2250 else | 2253 else |
2251 { | 2254 { |
2252 // The metadata is not existing yet: Ignore "oldRevision" | 2255 // The metadata is not existing yet: Ignore "oldRevision" |
2476 Operations operations(property, shared, value); | 2479 Operations operations(property, shared, value); |
2477 Apply(operations); | 2480 Apply(operations); |
2478 } | 2481 } |
2479 | 2482 |
2480 | 2483 |
2481 void StatelessDatabaseOperations::DeleteAttachment(const std::string& publicId, | 2484 bool StatelessDatabaseOperations::DeleteAttachment(const std::string& publicId, |
2482 FileContentType type) | 2485 FileContentType type, |
2486 bool hasRevision, | |
2487 int64_t revision) | |
2483 { | 2488 { |
2484 class Operations : public IReadWriteOperations | 2489 class Operations : public IReadWriteOperations |
2485 { | 2490 { |
2486 private: | 2491 private: |
2487 const std::string& publicId_; | 2492 const std::string& publicId_; |
2488 FileContentType type_; | 2493 FileContentType type_; |
2494 bool hasRevision_; | |
2495 int64_t revision_; | |
2496 bool found_; | |
2497 | |
2498 public: | |
2499 Operations(const std::string& publicId, | |
2500 FileContentType type, | |
2501 bool hasRevision, | |
2502 int64_t revision) : | |
2503 publicId_(publicId), | |
2504 type_(type), | |
2505 hasRevision_(hasRevision), | |
2506 revision_(revision), | |
2507 found_(false) | |
2508 { | |
2509 } | |
2510 | |
2511 bool HasFound() const | |
2512 { | |
2513 return found_; | |
2514 } | |
2489 | 2515 |
2490 public: | |
2491 Operations(const std::string& publicId, | |
2492 FileContentType type) : | |
2493 publicId_(publicId), | |
2494 type_(type) | |
2495 { | |
2496 } | |
2497 | |
2498 virtual void Apply(ReadWriteTransaction& transaction) ORTHANC_OVERRIDE | 2516 virtual void Apply(ReadWriteTransaction& transaction) ORTHANC_OVERRIDE |
2499 { | 2517 { |
2500 ResourceType resourceType; | 2518 ResourceType resourceType; |
2501 int64_t id; | 2519 int64_t id; |
2502 if (!transaction.LookupResource(id, resourceType, publicId_)) | 2520 if (!transaction.LookupResource(id, resourceType, publicId_)) |
2503 { | 2521 { |
2504 throw OrthancException(ErrorCode_UnknownResource); | 2522 throw OrthancException(ErrorCode_UnknownResource); |
2505 } | 2523 } |
2506 else | 2524 else |
2507 { | 2525 { |
2508 transaction.DeleteAttachment(id, type_); | 2526 FileInfo info; |
2527 int64_t expectedRevision; | |
2528 if (transaction.LookupAttachment(info, expectedRevision, id, type_)) | |
2529 { | |
2530 if (hasRevision_ && | |
2531 expectedRevision != revision_) | |
2532 { | |
2533 throw OrthancException(ErrorCode_Revision); | |
2534 } | |
2535 | |
2536 found_ = true; | |
2537 transaction.DeleteAttachment(id, type_); | |
2509 | 2538 |
2510 if (IsUserContentType(type_)) | 2539 if (IsUserContentType(type_)) |
2511 { | 2540 { |
2512 transaction.LogChange(id, ChangeType_UpdatedAttachment, resourceType, publicId_); | 2541 transaction.LogChange(id, ChangeType_UpdatedAttachment, resourceType, publicId_); |
2513 } | 2542 } |
2514 } | 2543 } |
2515 } | 2544 else |
2516 }; | 2545 { |
2517 | 2546 found_ = false; |
2518 Operations operations(publicId, type); | 2547 } |
2548 } | |
2549 } | |
2550 }; | |
2551 | |
2552 Operations operations(publicId, type, hasRevision, revision); | |
2519 Apply(operations); | 2553 Apply(operations); |
2554 return operations.HasFound(); | |
2520 } | 2555 } |
2521 | 2556 |
2522 | 2557 |
2523 void StatelessDatabaseOperations::LogChange(int64_t internalId, | 2558 void StatelessDatabaseOperations::LogChange(int64_t internalId, |
2524 ChangeType changeType, | 2559 ChangeType changeType, |
3016 | 3051 |
3017 // Attach the files to the newly created instance | 3052 // Attach the files to the newly created instance |
3018 for (Attachments::const_iterator it = attachments_.begin(); | 3053 for (Attachments::const_iterator it = attachments_.begin(); |
3019 it != attachments_.end(); ++it) | 3054 it != attachments_.end(); ++it) |
3020 { | 3055 { |
3021 transaction.AddAttachment(instanceId, *it); | 3056 transaction.AddAttachment(instanceId, *it, 0 /* this is the first revision */); |
3022 } | 3057 } |
3023 | 3058 |
3024 | 3059 |
3025 { | 3060 { |
3026 ResourcesContent content(true /* new resource, metadata can be set */); | 3061 ResourcesContent content(true /* new resource, metadata can be set */); |
3217 Apply(operations); | 3252 Apply(operations); |
3218 return operations.GetStoreStatus(); | 3253 return operations.GetStoreStatus(); |
3219 } | 3254 } |
3220 | 3255 |
3221 | 3256 |
3222 StoreStatus StatelessDatabaseOperations::AddAttachment(const FileInfo& attachment, | 3257 StoreStatus StatelessDatabaseOperations::AddAttachment(int64_t& newRevision, |
3258 const FileInfo& attachment, | |
3223 const std::string& publicId, | 3259 const std::string& publicId, |
3224 uint64_t maximumStorageSize, | 3260 uint64_t maximumStorageSize, |
3225 unsigned int maximumPatients) | 3261 unsigned int maximumPatients, |
3262 bool hasOldRevision, | |
3263 int64_t oldRevision) | |
3226 { | 3264 { |
3227 class Operations : public IReadWriteOperations | 3265 class Operations : public IReadWriteOperations |
3228 { | 3266 { |
3229 private: | 3267 private: |
3268 int64_t& newRevision_; | |
3230 StoreStatus status_; | 3269 StoreStatus status_; |
3231 const FileInfo& attachment_; | 3270 const FileInfo& attachment_; |
3232 const std::string& publicId_; | 3271 const std::string& publicId_; |
3233 uint64_t maximumStorageSize_; | 3272 uint64_t maximumStorageSize_; |
3234 unsigned int maximumPatientCount_; | 3273 unsigned int maximumPatientCount_; |
3235 | 3274 bool hasOldRevision_; |
3236 public: | 3275 int64_t oldRevision_; |
3237 Operations(const FileInfo& attachment, | 3276 |
3277 public: | |
3278 Operations(int64_t& newRevision, | |
3279 const FileInfo& attachment, | |
3238 const std::string& publicId, | 3280 const std::string& publicId, |
3239 uint64_t maximumStorageSize, | 3281 uint64_t maximumStorageSize, |
3240 unsigned int maximumPatientCount) : | 3282 unsigned int maximumPatientCount, |
3283 bool hasOldRevision, | |
3284 int64_t oldRevision) : | |
3285 newRevision_(newRevision), | |
3241 status_(StoreStatus_Failure), | 3286 status_(StoreStatus_Failure), |
3242 attachment_(attachment), | 3287 attachment_(attachment), |
3243 publicId_(publicId), | 3288 publicId_(publicId), |
3244 maximumStorageSize_(maximumStorageSize), | 3289 maximumStorageSize_(maximumStorageSize), |
3245 maximumPatientCount_(maximumPatientCount) | 3290 maximumPatientCount_(maximumPatientCount), |
3291 hasOldRevision_(hasOldRevision), | |
3292 oldRevision_(oldRevision) | |
3246 { | 3293 { |
3247 } | 3294 } |
3248 | 3295 |
3249 StoreStatus GetStatus() const | 3296 StoreStatus GetStatus() const |
3250 { | 3297 { |
3259 { | 3306 { |
3260 status_ = StoreStatus_Failure; // Inexistent resource | 3307 status_ = StoreStatus_Failure; // Inexistent resource |
3261 } | 3308 } |
3262 else | 3309 else |
3263 { | 3310 { |
3264 // Remove possible previous attachment | 3311 // Possibly remove previous attachment |
3265 transaction.DeleteAttachment(resourceId, attachment_.GetContentType()); | 3312 { |
3313 FileInfo oldFile; | |
3314 int64_t expectedRevision; | |
3315 if (transaction.LookupAttachment(oldFile, expectedRevision, resourceId, attachment_.GetContentType())) | |
3316 { | |
3317 if (hasOldRevision_ && | |
3318 expectedRevision != oldRevision_) | |
3319 { | |
3320 throw OrthancException(ErrorCode_Revision); | |
3321 } | |
3322 else | |
3323 { | |
3324 newRevision_ = expectedRevision + 1; | |
3325 transaction.DeleteAttachment(resourceId, attachment_.GetContentType()); | |
3326 } | |
3327 } | |
3328 else | |
3329 { | |
3330 // The attachment is not existing yet: Ignore "oldRevision" | |
3331 // and initialize a new sequence of revisions | |
3332 newRevision_ = 0; | |
3333 } | |
3334 } | |
3266 | 3335 |
3267 // Locate the patient of the target resource | 3336 // Locate the patient of the target resource |
3268 int64_t patientId = resourceId; | 3337 int64_t patientId = resourceId; |
3269 for (;;) | 3338 for (;;) |
3270 { | 3339 { |
3284 // Possibly apply the recycling mechanism while preserving this patient | 3353 // Possibly apply the recycling mechanism while preserving this patient |
3285 assert(transaction.GetResourceType(patientId) == ResourceType_Patient); | 3354 assert(transaction.GetResourceType(patientId) == ResourceType_Patient); |
3286 transaction.Recycle(maximumStorageSize_, maximumPatientCount_, | 3355 transaction.Recycle(maximumStorageSize_, maximumPatientCount_, |
3287 attachment_.GetCompressedSize(), transaction.GetPublicId(patientId)); | 3356 attachment_.GetCompressedSize(), transaction.GetPublicId(patientId)); |
3288 | 3357 |
3289 transaction.AddAttachment(resourceId, attachment_); | 3358 transaction.AddAttachment(resourceId, attachment_, newRevision_); |
3290 | 3359 |
3291 if (IsUserContentType(attachment_.GetContentType())) | 3360 if (IsUserContentType(attachment_.GetContentType())) |
3292 { | 3361 { |
3293 transaction.LogChange(resourceId, ChangeType_UpdatedAttachment, resourceType, publicId_); | 3362 transaction.LogChange(resourceId, ChangeType_UpdatedAttachment, resourceType, publicId_); |
3294 } | 3363 } |
3299 } | 3368 } |
3300 } | 3369 } |
3301 }; | 3370 }; |
3302 | 3371 |
3303 | 3372 |
3304 Operations operations(attachment, publicId, maximumStorageSize, maximumPatients); | 3373 Operations operations(newRevision, attachment, publicId, maximumStorageSize, maximumPatients, hasOldRevision, oldRevision); |
3305 Apply(operations); | 3374 Apply(operations); |
3306 return operations.GetStatus(); | 3375 return operations.GetStatus(); |
3307 } | 3376 } |
3308 } | 3377 } |