Mercurial > hg > orthanc
comparison OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp @ 4623:95ffe3b6ef7c db-changes
handling of revisions for metadata
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 16 Apr 2021 17:13:03 +0200 |
parents | fda80844b920 |
children | f7d5372b59b3 |
comparison
equal
deleted
inserted
replaced
4622:9086aeb9d9d2 | 4623:95ffe3b6ef7c |
---|---|
1365 operations.Apply(*this, result, publicId); | 1365 operations.Apply(*this, result, publicId); |
1366 } | 1366 } |
1367 | 1367 |
1368 | 1368 |
1369 bool StatelessDatabaseOperations::LookupMetadata(std::string& target, | 1369 bool StatelessDatabaseOperations::LookupMetadata(std::string& target, |
1370 int64_t& revision, | |
1370 const std::string& publicId, | 1371 const std::string& publicId, |
1371 ResourceType expectedType, | 1372 ResourceType expectedType, |
1372 MetadataType type) | 1373 MetadataType type) |
1373 { | 1374 { |
1374 class Operations : public ReadOnlyOperationsT5<bool&, std::string&, const std::string&, ResourceType, MetadataType> | 1375 class Operations : public ReadOnlyOperationsT6<bool&, std::string&, int64_t&, |
1376 const std::string&, ResourceType, MetadataType> | |
1375 { | 1377 { |
1376 public: | 1378 public: |
1377 virtual void ApplyTuple(ReadOnlyTransaction& transaction, | 1379 virtual void ApplyTuple(ReadOnlyTransaction& transaction, |
1378 const Tuple& tuple) ORTHANC_OVERRIDE | 1380 const Tuple& tuple) ORTHANC_OVERRIDE |
1379 { | 1381 { |
1380 ResourceType rtype; | 1382 ResourceType resourceType; |
1381 int64_t id; | 1383 int64_t id; |
1382 if (!transaction.LookupResource(id, rtype, tuple.get<2>()) || | 1384 if (!transaction.LookupResource(id, resourceType, tuple.get<3>()) || |
1383 rtype != tuple.get<3>()) | 1385 resourceType != tuple.get<4>()) |
1384 { | 1386 { |
1385 throw OrthancException(ErrorCode_UnknownResource); | 1387 throw OrthancException(ErrorCode_UnknownResource); |
1386 } | 1388 } |
1387 else | 1389 else |
1388 { | 1390 { |
1389 tuple.get<0>() = transaction.LookupMetadata(tuple.get<1>(), id, tuple.get<4>()); | 1391 tuple.get<0>() = transaction.LookupMetadata(tuple.get<1>(), tuple.get<2>(), id, tuple.get<5>()); |
1390 } | 1392 } |
1391 } | 1393 } |
1392 }; | 1394 }; |
1393 | 1395 |
1394 bool found; | 1396 bool found; |
1395 Operations operations; | 1397 Operations operations; |
1396 operations.Apply(*this, found, target, publicId, expectedType, type); | 1398 operations.Apply(*this, found, target, revision, publicId, expectedType, type); |
1397 return found; | 1399 return found; |
1398 } | 1400 } |
1399 | 1401 |
1400 | 1402 |
1401 void StatelessDatabaseOperations::ListAvailableAttachments(std::set<FileContentType>& target, | 1403 void StatelessDatabaseOperations::ListAvailableAttachments(std::set<FileContentType>& target, |
2186 LOG(INFO) << "Patient " << publicId << " has been unprotected"; | 2188 LOG(INFO) << "Patient " << publicId << " has been unprotected"; |
2187 } | 2189 } |
2188 } | 2190 } |
2189 | 2191 |
2190 | 2192 |
2191 void StatelessDatabaseOperations::SetMetadata(const std::string& publicId, | 2193 void StatelessDatabaseOperations::SetMetadata(int64_t& newRevision, |
2194 const std::string& publicId, | |
2192 MetadataType type, | 2195 MetadataType type, |
2193 const std::string& value) | 2196 const std::string& value, |
2197 bool hasOldRevision, | |
2198 int64_t oldRevision) | |
2199 { | |
2200 class Operations : public IReadWriteOperations | |
2201 { | |
2202 private: | |
2203 int64_t& newRevision_; | |
2204 const std::string& publicId_; | |
2205 MetadataType type_; | |
2206 const std::string& value_; | |
2207 bool hasOldRevision_; | |
2208 int64_t oldRevision_; | |
2209 | |
2210 public: | |
2211 Operations(int64_t& newRevision, | |
2212 const std::string& publicId, | |
2213 MetadataType type, | |
2214 const std::string& value, | |
2215 bool hasOldRevision, | |
2216 int64_t oldRevision) : | |
2217 newRevision_(newRevision), | |
2218 publicId_(publicId), | |
2219 type_(type), | |
2220 value_(value), | |
2221 hasOldRevision_(hasOldRevision), | |
2222 oldRevision_(oldRevision) | |
2223 { | |
2224 } | |
2225 | |
2226 virtual void Apply(ReadWriteTransaction& transaction) ORTHANC_OVERRIDE | |
2227 { | |
2228 ResourceType resourceType; | |
2229 int64_t id; | |
2230 if (!transaction.LookupResource(id, resourceType, publicId_)) | |
2231 { | |
2232 throw OrthancException(ErrorCode_UnknownResource); | |
2233 } | |
2234 else | |
2235 { | |
2236 std::string oldValue; | |
2237 int64_t expectedRevision; | |
2238 if (transaction.LookupMetadata(oldValue, expectedRevision, id, type_)) | |
2239 { | |
2240 if (hasOldRevision_ && | |
2241 expectedRevision != oldRevision_) | |
2242 { | |
2243 throw OrthancException(ErrorCode_Revision); | |
2244 } | |
2245 else | |
2246 { | |
2247 newRevision_ = oldRevision_ + 1; | |
2248 } | |
2249 } | |
2250 else | |
2251 { | |
2252 // The metadata is not existing yet: Ignore "oldRevision" | |
2253 // and initialize a new sequence of revisions | |
2254 newRevision_ = 0; | |
2255 } | |
2256 | |
2257 transaction.SetMetadata(id, type_, value_, newRevision_); | |
2258 | |
2259 if (IsUserMetadata(type_)) | |
2260 { | |
2261 transaction.LogChange(id, ChangeType_UpdatedMetadata, resourceType, publicId_); | |
2262 } | |
2263 } | |
2264 } | |
2265 }; | |
2266 | |
2267 Operations operations(newRevision, publicId, type, value, hasOldRevision, oldRevision); | |
2268 Apply(operations); | |
2269 } | |
2270 | |
2271 | |
2272 void StatelessDatabaseOperations::OverwriteMetadata(const std::string& publicId, | |
2273 MetadataType type, | |
2274 const std::string& value) | |
2275 { | |
2276 int64_t newRevision; // Unused | |
2277 SetMetadata(newRevision, publicId, type, value, false /* no old revision */, -1 /* dummy */); | |
2278 } | |
2279 | |
2280 | |
2281 bool StatelessDatabaseOperations::DeleteMetadata(const std::string& publicId, | |
2282 MetadataType type, | |
2283 bool hasRevision, | |
2284 int64_t revision) | |
2194 { | 2285 { |
2195 class Operations : public IReadWriteOperations | 2286 class Operations : public IReadWriteOperations |
2196 { | 2287 { |
2197 private: | 2288 private: |
2198 const std::string& publicId_; | 2289 const std::string& publicId_; |
2199 MetadataType type_; | 2290 MetadataType type_; |
2200 const std::string& value_; | 2291 bool hasRevision_; |
2292 int64_t revision_; | |
2293 bool found_; | |
2201 | 2294 |
2202 public: | 2295 public: |
2203 Operations(const std::string& publicId, | 2296 Operations(const std::string& publicId, |
2204 MetadataType type, | 2297 MetadataType type, |
2205 const std::string& value) : | 2298 bool hasRevision, |
2299 int64_t revision) : | |
2206 publicId_(publicId), | 2300 publicId_(publicId), |
2207 type_(type), | 2301 type_(type), |
2208 value_(value) | 2302 hasRevision_(hasRevision), |
2209 { | 2303 revision_(revision), |
2304 found_(false) | |
2305 { | |
2306 } | |
2307 | |
2308 bool HasFound() const | |
2309 { | |
2310 return found_; | |
2210 } | 2311 } |
2211 | 2312 |
2212 virtual void Apply(ReadWriteTransaction& transaction) ORTHANC_OVERRIDE | 2313 virtual void Apply(ReadWriteTransaction& transaction) ORTHANC_OVERRIDE |
2213 { | 2314 { |
2214 ResourceType rtype; | 2315 ResourceType resourceType; |
2215 int64_t id; | 2316 int64_t id; |
2216 if (!transaction.LookupResource(id, rtype, publicId_)) | 2317 if (!transaction.LookupResource(id, resourceType, publicId_)) |
2217 { | 2318 { |
2218 throw OrthancException(ErrorCode_UnknownResource); | 2319 throw OrthancException(ErrorCode_UnknownResource); |
2219 } | 2320 } |
2220 else | 2321 else |
2221 { | 2322 { |
2222 transaction.SetMetadata(id, type_, value_); | 2323 std::string s; |
2223 | 2324 int64_t expectedRevision; |
2224 if (IsUserMetadata(type_)) | 2325 if (transaction.LookupMetadata(s, expectedRevision, id, type_)) |
2225 { | 2326 { |
2226 transaction.LogChange(id, ChangeType_UpdatedMetadata, rtype, publicId_); | 2327 if (hasRevision_ && |
2227 } | 2328 expectedRevision != revision_) |
2228 } | 2329 { |
2229 } | 2330 throw OrthancException(ErrorCode_Revision); |
2230 }; | 2331 } |
2231 | 2332 |
2232 Operations operations(publicId, type, value); | 2333 found_ = true; |
2334 transaction.DeleteMetadata(id, type_); | |
2335 | |
2336 if (IsUserMetadata(type_)) | |
2337 { | |
2338 transaction.LogChange(id, ChangeType_UpdatedMetadata, resourceType, publicId_); | |
2339 } | |
2340 } | |
2341 else | |
2342 { | |
2343 found_ = false; | |
2344 } | |
2345 } | |
2346 } | |
2347 }; | |
2348 | |
2349 Operations operations(publicId, type, hasRevision, revision); | |
2233 Apply(operations); | 2350 Apply(operations); |
2234 } | 2351 return operations.HasFound(); |
2235 | |
2236 | |
2237 void StatelessDatabaseOperations::DeleteMetadata(const std::string& publicId, | |
2238 MetadataType type) | |
2239 { | |
2240 class Operations : public IReadWriteOperations | |
2241 { | |
2242 private: | |
2243 const std::string& publicId_; | |
2244 MetadataType type_; | |
2245 | |
2246 public: | |
2247 Operations(const std::string& publicId, | |
2248 MetadataType type) : | |
2249 publicId_(publicId), | |
2250 type_(type) | |
2251 { | |
2252 } | |
2253 | |
2254 virtual void Apply(ReadWriteTransaction& transaction) ORTHANC_OVERRIDE | |
2255 { | |
2256 ResourceType rtype; | |
2257 int64_t id; | |
2258 if (!transaction.LookupResource(id, rtype, publicId_)) | |
2259 { | |
2260 throw OrthancException(ErrorCode_UnknownResource); | |
2261 } | |
2262 else | |
2263 { | |
2264 transaction.DeleteMetadata(id, type_); | |
2265 | |
2266 if (IsUserMetadata(type_)) | |
2267 { | |
2268 transaction.LogChange(id, ChangeType_UpdatedMetadata, rtype, publicId_); | |
2269 } | |
2270 } | |
2271 } | |
2272 }; | |
2273 | |
2274 Operations operations(publicId, type); | |
2275 Apply(operations); | |
2276 } | 2352 } |
2277 | 2353 |
2278 | 2354 |
2279 uint64_t StatelessDatabaseOperations::IncrementGlobalSequence(GlobalProperty sequence, | 2355 uint64_t StatelessDatabaseOperations::IncrementGlobalSequence(GlobalProperty sequence, |
2280 bool shared) | 2356 bool shared) |
2419 { | 2495 { |
2420 } | 2496 } |
2421 | 2497 |
2422 virtual void Apply(ReadWriteTransaction& transaction) ORTHANC_OVERRIDE | 2498 virtual void Apply(ReadWriteTransaction& transaction) ORTHANC_OVERRIDE |
2423 { | 2499 { |
2424 ResourceType rtype; | 2500 ResourceType resourceType; |
2425 int64_t id; | 2501 int64_t id; |
2426 if (!transaction.LookupResource(id, rtype, publicId_)) | 2502 if (!transaction.LookupResource(id, resourceType, publicId_)) |
2427 { | 2503 { |
2428 throw OrthancException(ErrorCode_UnknownResource); | 2504 throw OrthancException(ErrorCode_UnknownResource); |
2429 } | 2505 } |
2430 else | 2506 else |
2431 { | 2507 { |
2432 transaction.DeleteAttachment(id, type_); | 2508 transaction.DeleteAttachment(id, type_); |
2433 | 2509 |
2434 if (IsUserContentType(type_)) | 2510 if (IsUserContentType(type_)) |
2435 { | 2511 { |
2436 transaction.LogChange(id, ChangeType_UpdatedAttachment, rtype, publicId_); | 2512 transaction.LogChange(id, ChangeType_UpdatedAttachment, resourceType, publicId_); |
2437 } | 2513 } |
2438 } | 2514 } |
2439 } | 2515 } |
2440 }; | 2516 }; |
2441 | 2517 |
2510 private: | 2586 private: |
2511 DicomMap summary_; | 2587 DicomMap summary_; |
2512 std::unique_ptr<DicomInstanceHasher> hasher_; | 2588 std::unique_ptr<DicomInstanceHasher> hasher_; |
2513 bool hasTransferSyntax_; | 2589 bool hasTransferSyntax_; |
2514 DicomTransferSyntax transferSyntax_; | 2590 DicomTransferSyntax transferSyntax_; |
2591 | |
2592 static void ReplaceMetadata(ReadWriteTransaction& transaction, | |
2593 int64_t instance, | |
2594 MetadataType metadata, | |
2595 const std::string& value) | |
2596 { | |
2597 std::string oldValue; | |
2598 int64_t oldRevision; | |
2599 | |
2600 if (transaction.LookupMetadata(oldValue, oldRevision, instance, metadata)) | |
2601 { | |
2602 transaction.SetMetadata(instance, metadata, value, oldRevision + 1); | |
2603 } | |
2604 else | |
2605 { | |
2606 transaction.SetMetadata(instance, metadata, value, 0); | |
2607 } | |
2608 } | |
2515 | 2609 |
2516 public: | 2610 public: |
2517 explicit Operations(const ParsedDicomFile& dicom) | 2611 explicit Operations(const ParsedDicomFile& dicom) |
2518 { | 2612 { |
2519 OrthancConfiguration::DefaultExtractDicomSummary(summary_, dicom); | 2613 OrthancConfiguration::DefaultExtractDicomSummary(summary_, dicom); |
2546 transaction.ClearMainDicomTags(study); | 2640 transaction.ClearMainDicomTags(study); |
2547 transaction.ClearMainDicomTags(series); | 2641 transaction.ClearMainDicomTags(series); |
2548 transaction.ClearMainDicomTags(instance); | 2642 transaction.ClearMainDicomTags(instance); |
2549 | 2643 |
2550 { | 2644 { |
2551 ResourcesContent content; | 2645 ResourcesContent content(false /* prevent the setting of metadata */); |
2552 content.AddResource(patient, ResourceType_Patient, summary_); | 2646 content.AddResource(patient, ResourceType_Patient, summary_); |
2553 content.AddResource(study, ResourceType_Study, summary_); | 2647 content.AddResource(study, ResourceType_Study, summary_); |
2554 content.AddResource(series, ResourceType_Series, summary_); | 2648 content.AddResource(series, ResourceType_Series, summary_); |
2555 content.AddResource(instance, ResourceType_Instance, summary_); | 2649 content.AddResource(instance, ResourceType_Instance, summary_); |
2556 transaction.SetResourcesContent(content); | 2650 transaction.SetResourcesContent(content); |
2557 } | 2651 } |
2558 | 2652 |
2559 if (hasTransferSyntax_) | 2653 if (hasTransferSyntax_) |
2560 { | 2654 { |
2561 transaction.SetMetadata(instance, MetadataType_Instance_TransferSyntax, GetTransferSyntaxUid(transferSyntax_)); | 2655 ReplaceMetadata(transaction, instance, MetadataType_Instance_TransferSyntax, GetTransferSyntaxUid(transferSyntax_)); |
2562 } | 2656 } |
2563 | 2657 |
2564 const DicomValue* value; | 2658 const DicomValue* value; |
2565 if ((value = summary_.TestAndGetValue(DICOM_TAG_SOP_CLASS_UID)) != NULL && | 2659 if ((value = summary_.TestAndGetValue(DICOM_TAG_SOP_CLASS_UID)) != NULL && |
2566 !value->IsNull() && | 2660 !value->IsNull() && |
2567 !value->IsBinary()) | 2661 !value->IsBinary()) |
2568 { | 2662 { |
2569 transaction.SetMetadata(instance, MetadataType_Instance_SopClassUid, value->GetContent()); | 2663 ReplaceMetadata(transaction, instance, MetadataType_Instance_SopClassUid, value->GetContent()); |
2570 } | 2664 } |
2571 } | 2665 } |
2572 }; | 2666 }; |
2573 | 2667 |
2574 Operations operations(dicom); | 2668 Operations operations(dicom); |
2927 transaction.AddAttachment(instanceId, *it); | 3021 transaction.AddAttachment(instanceId, *it); |
2928 } | 3022 } |
2929 | 3023 |
2930 | 3024 |
2931 { | 3025 { |
2932 ResourcesContent content; | 3026 ResourcesContent content(true /* new resource, metadata can be set */); |
2933 | 3027 |
2934 // Populate the tags of the newly-created resources | 3028 // Populate the tags of the newly-created resources |
2935 | 3029 |
2936 content.AddResource(instanceId, ResourceType_Instance, dicomSummary_); | 3030 content.AddResource(instanceId, ResourceType_Instance, dicomSummary_); |
2937 | 3031 |