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