Mercurial > hg > orthanc
comparison OrthancServer/Sources/Database/StatelessDatabaseOperations.h @ 4586:1d96fe7e054e db-changes
taking StatelessDatabaseOperations out of ServerIndex
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 09 Mar 2021 18:24:59 +0100 |
parents | |
children | 888868a5dc4e |
comparison
equal
deleted
inserted
replaced
4585:f0bdd99f3d81 | 4586:1d96fe7e054e |
---|---|
1 /** | |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * Copyright (C) 2017-2021 Osimis S.A., Belgium | |
6 * | |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU General Public License as | |
9 * published by the Free Software Foundation, either version 3 of the | |
10 * License, or (at your option) any later version. | |
11 * | |
12 * In addition, as a special exception, the copyright holders of this | |
13 * program give permission to link the code of its release with the | |
14 * OpenSSL project's "OpenSSL" library (or with modified versions of it | |
15 * that use the same license as the "OpenSSL" library), and distribute | |
16 * the linked executables. You must obey the GNU General Public License | |
17 * in all respects for all of the code used other than "OpenSSL". If you | |
18 * modify file(s) with this exception, you may extend this exception to | |
19 * your version of the file(s), but you are not obligated to do so. If | |
20 * you do not wish to do so, delete this exception statement from your | |
21 * version. If you delete this exception statement from all source files | |
22 * in the program, then also delete it here. | |
23 * | |
24 * This program is distributed in the hope that it will be useful, but | |
25 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
27 * General Public License for more details. | |
28 * | |
29 * You should have received a copy of the GNU General Public License | |
30 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
31 **/ | |
32 | |
33 | |
34 #pragma once | |
35 | |
36 #include "../../../OrthancFramework/Sources/DicomFormat/DicomMap.h" | |
37 | |
38 #include "IDatabaseWrapper.h" | |
39 #include "../DicomInstanceOrigin.h" | |
40 | |
41 #include <boost/thread/mutex.hpp> // TODO - REMOVE | |
42 | |
43 | |
44 namespace Orthanc | |
45 { | |
46 class DatabaseLookup; | |
47 class ParsedDicomFile; | |
48 class ServerIndexChange; | |
49 | |
50 class StatelessDatabaseOperations : public boost::noncopyable | |
51 { | |
52 public: | |
53 typedef std::list<FileInfo> Attachments; | |
54 typedef std::map<std::pair<ResourceType, MetadataType>, std::string> MetadataMap; | |
55 | |
56 class ITransactionContext : public boost::noncopyable | |
57 { | |
58 public: | |
59 virtual ~ITransactionContext() | |
60 { | |
61 } | |
62 | |
63 virtual void Commit() = 0; | |
64 | |
65 virtual int64_t GetCompressedSizeDelta() = 0; | |
66 | |
67 virtual bool IsUnstableResource(int64_t id) = 0; | |
68 | |
69 virtual bool LookupRemainingLevel(std::string& remainingPublicId /* out */, | |
70 ResourceType& remainingLevel /* out */) = 0; | |
71 | |
72 virtual void MarkAsUnstable(int64_t id, | |
73 Orthanc::ResourceType type, | |
74 const std::string& publicId) = 0; | |
75 | |
76 virtual void SignalAttachmentsAdded(uint64_t compressedSize) = 0; | |
77 | |
78 virtual void SignalChange(const ServerIndexChange& change) = 0; | |
79 }; | |
80 | |
81 | |
82 class ITransactionContextFactory : public boost::noncopyable | |
83 { | |
84 public: | |
85 virtual ~ITransactionContextFactory() | |
86 { | |
87 } | |
88 | |
89 virtual ITransactionContext* Create() = 0; | |
90 }; | |
91 | |
92 | |
93 class ReadOnlyTransaction : public boost::noncopyable | |
94 { | |
95 private: | |
96 ITransactionContext& context_; | |
97 | |
98 protected: | |
99 IDatabaseWrapper& db_; | |
100 | |
101 public: | |
102 explicit ReadOnlyTransaction(IDatabaseWrapper& db, | |
103 ITransactionContext& context) : | |
104 context_(context), | |
105 db_(db) | |
106 { | |
107 } | |
108 | |
109 ITransactionContext& GetTransactionContext() | |
110 { | |
111 return context_; | |
112 } | |
113 | |
114 /** | |
115 * Higher-level constructions | |
116 **/ | |
117 | |
118 SeriesStatus GetSeriesStatus(int64_t id, | |
119 int64_t expectedNumberOfInstances); | |
120 | |
121 | |
122 /** | |
123 * Read-only methods from "IDatabaseWrapper" | |
124 **/ | |
125 | |
126 void ApplyLookupResources(std::list<std::string>& resourcesId, | |
127 std::list<std::string>* instancesId, // Can be NULL if not needed | |
128 const std::vector<DatabaseConstraint>& lookup, | |
129 ResourceType queryLevel, | |
130 size_t limit) | |
131 { | |
132 return db_.ApplyLookupResources(resourcesId, instancesId, lookup, queryLevel, limit); | |
133 } | |
134 | |
135 void GetAllMetadata(std::map<MetadataType, std::string>& target, | |
136 int64_t id) | |
137 { | |
138 db_.GetAllMetadata(target, id); | |
139 } | |
140 | |
141 void GetAllPublicIds(std::list<std::string>& target, | |
142 ResourceType resourceType) | |
143 { | |
144 return db_.GetAllPublicIds(target, resourceType); | |
145 } | |
146 | |
147 void GetAllPublicIds(std::list<std::string>& target, | |
148 ResourceType resourceType, | |
149 size_t since, | |
150 size_t limit) | |
151 { | |
152 return db_.GetAllPublicIds(target, resourceType, since, limit); | |
153 } | |
154 | |
155 void GetChanges(std::list<ServerIndexChange>& target /*out*/, | |
156 bool& done /*out*/, | |
157 int64_t since, | |
158 uint32_t maxResults) | |
159 { | |
160 db_.GetChanges(target, done, since, maxResults); | |
161 } | |
162 | |
163 void GetChildrenInternalId(std::list<int64_t>& target, | |
164 int64_t id) | |
165 { | |
166 db_.GetChildrenInternalId(target, id); | |
167 } | |
168 | |
169 void GetChildrenPublicId(std::list<std::string>& target, | |
170 int64_t id) | |
171 { | |
172 db_.GetChildrenPublicId(target, id); | |
173 } | |
174 | |
175 void GetExportedResources(std::list<ExportedResource>& target /*out*/, | |
176 bool& done /*out*/, | |
177 int64_t since, | |
178 uint32_t maxResults) | |
179 { | |
180 return db_.GetExportedResources(target, done, since, maxResults); | |
181 } | |
182 | |
183 void GetLastChange(std::list<ServerIndexChange>& target /*out*/) | |
184 { | |
185 db_.GetLastChange(target); | |
186 } | |
187 | |
188 void GetLastExportedResource(std::list<ExportedResource>& target /*out*/) | |
189 { | |
190 return db_.GetLastExportedResource(target); | |
191 } | |
192 | |
193 int64_t GetLastChangeIndex() | |
194 { | |
195 return db_.GetLastChangeIndex(); | |
196 } | |
197 | |
198 void GetMainDicomTags(DicomMap& map, | |
199 int64_t id) | |
200 { | |
201 db_.GetMainDicomTags(map, id); | |
202 } | |
203 | |
204 std::string GetPublicId(int64_t resourceId) | |
205 { | |
206 return db_.GetPublicId(resourceId); | |
207 } | |
208 | |
209 uint64_t GetResourceCount(ResourceType resourceType) | |
210 { | |
211 return db_.GetResourceCount(resourceType); | |
212 } | |
213 | |
214 ResourceType GetResourceType(int64_t resourceId) | |
215 { | |
216 return db_.GetResourceType(resourceId); | |
217 } | |
218 | |
219 uint64_t GetTotalCompressedSize() | |
220 { | |
221 return db_.GetTotalCompressedSize(); | |
222 } | |
223 | |
224 uint64_t GetTotalUncompressedSize() | |
225 { | |
226 return db_.GetTotalUncompressedSize(); | |
227 } | |
228 | |
229 bool IsProtectedPatient(int64_t internalId) | |
230 { | |
231 return db_.IsProtectedPatient(internalId); | |
232 } | |
233 | |
234 void ListAvailableAttachments(std::set<FileContentType>& target, | |
235 int64_t id) | |
236 { | |
237 db_.ListAvailableAttachments(target, id); | |
238 } | |
239 | |
240 bool LookupAttachment(FileInfo& attachment, | |
241 int64_t id, | |
242 FileContentType contentType) | |
243 { | |
244 return db_.LookupAttachment(attachment, id, contentType); | |
245 } | |
246 | |
247 bool LookupGlobalProperty(std::string& target, | |
248 GlobalProperty property) | |
249 { | |
250 return db_.LookupGlobalProperty(target, property); | |
251 } | |
252 | |
253 bool LookupMetadata(std::string& target, | |
254 int64_t id, | |
255 MetadataType type) | |
256 { | |
257 return db_.LookupMetadata(target, id, type); | |
258 } | |
259 | |
260 bool LookupParent(int64_t& parentId, | |
261 int64_t resourceId) | |
262 { | |
263 return db_.LookupParent(parentId, resourceId); | |
264 } | |
265 | |
266 bool LookupResource(int64_t& id, | |
267 ResourceType& type, | |
268 const std::string& publicId) | |
269 { | |
270 return db_.LookupResource(id, type, publicId); | |
271 } | |
272 | |
273 bool LookupResourceAndParent(int64_t& id, | |
274 ResourceType& type, | |
275 std::string& parentPublicId, | |
276 const std::string& publicId) | |
277 { | |
278 return db_.LookupResourceAndParent(id, type, parentPublicId, publicId); | |
279 } | |
280 }; | |
281 | |
282 | |
283 class ReadWriteTransaction : public ReadOnlyTransaction | |
284 { | |
285 public: | |
286 ReadWriteTransaction(IDatabaseWrapper& db, | |
287 ITransactionContext& context) : | |
288 ReadOnlyTransaction(db, context) | |
289 { | |
290 } | |
291 | |
292 void AddAttachment(int64_t id, | |
293 const FileInfo& attachment) | |
294 { | |
295 db_.AddAttachment(id, attachment); | |
296 } | |
297 | |
298 void ClearChanges() | |
299 { | |
300 db_.ClearChanges(); | |
301 } | |
302 | |
303 void ClearExportedResources() | |
304 { | |
305 db_.ClearExportedResources(); | |
306 } | |
307 | |
308 void ClearMainDicomTags(int64_t id) | |
309 { | |
310 return db_.ClearMainDicomTags(id); | |
311 } | |
312 | |
313 bool CreateInstance(IDatabaseWrapper::CreateInstanceResult& result, /* out */ | |
314 int64_t& instanceId, /* out */ | |
315 const std::string& patient, | |
316 const std::string& study, | |
317 const std::string& series, | |
318 const std::string& instance) | |
319 { | |
320 return db_.CreateInstance(result, instanceId, patient, study, series, instance); | |
321 } | |
322 | |
323 void DeleteAttachment(int64_t id, | |
324 FileContentType attachment) | |
325 { | |
326 return db_.DeleteAttachment(id, attachment); | |
327 } | |
328 | |
329 void DeleteMetadata(int64_t id, | |
330 MetadataType type) | |
331 { | |
332 db_.DeleteMetadata(id, type); | |
333 } | |
334 | |
335 void DeleteResource(int64_t id) | |
336 { | |
337 db_.DeleteResource(id); | |
338 } | |
339 | |
340 void LogChange(int64_t internalId, | |
341 ChangeType changeType, | |
342 ResourceType resourceType, | |
343 const std::string& publicId); | |
344 | |
345 void LogExportedResource(const ExportedResource& resource) | |
346 { | |
347 db_.LogExportedResource(resource); | |
348 } | |
349 | |
350 void SetGlobalProperty(GlobalProperty property, | |
351 const std::string& value) | |
352 { | |
353 db_.SetGlobalProperty(property, value); | |
354 } | |
355 | |
356 void SetMetadata(int64_t id, | |
357 MetadataType type, | |
358 const std::string& value) | |
359 { | |
360 return db_.SetMetadata(id, type, value); | |
361 } | |
362 | |
363 void SetProtectedPatient(int64_t internalId, | |
364 bool isProtected) | |
365 { | |
366 db_.SetProtectedPatient(internalId, isProtected); | |
367 } | |
368 | |
369 void SetResourcesContent(const ResourcesContent& content) | |
370 { | |
371 db_.SetResourcesContent(content); | |
372 } | |
373 | |
374 void Recycle(uint64_t maximumStorageSize, | |
375 unsigned int maximumPatients, | |
376 uint64_t addedInstanceSize, | |
377 const std::string& newPatientId); | |
378 }; | |
379 | |
380 | |
381 class IReadOnlyOperations : public boost::noncopyable | |
382 { | |
383 public: | |
384 virtual ~IReadOnlyOperations() | |
385 { | |
386 } | |
387 | |
388 virtual void Apply(ReadOnlyTransaction& transaction) = 0; | |
389 }; | |
390 | |
391 | |
392 class IReadWriteOperations : public boost::noncopyable | |
393 { | |
394 public: | |
395 virtual ~IReadWriteOperations() | |
396 { | |
397 } | |
398 | |
399 virtual void Apply(ReadWriteTransaction& transaction) = 0; | |
400 }; | |
401 | |
402 | |
403 private: | |
404 class MainDicomTagsRegistry; | |
405 class Transaction; | |
406 | |
407 IDatabaseWrapper& db_; | |
408 boost::mutex databaseMutex_; // TODO - REMOVE | |
409 std::unique_ptr<ITransactionContextFactory> factory_; | |
410 unsigned int maxRetries_; | |
411 std::unique_ptr<MainDicomTagsRegistry> mainDicomTagsRegistry_; | |
412 | |
413 void NormalizeLookup(std::vector<DatabaseConstraint>& target, | |
414 const DatabaseLookup& source, | |
415 ResourceType level) const; | |
416 | |
417 void ApplyInternal(IReadOnlyOperations* readOperations, | |
418 IReadWriteOperations* writeOperations); | |
419 | |
420 protected: | |
421 void StandaloneRecycling(uint64_t maximumStorageSize, | |
422 unsigned int maximumPatientCount); | |
423 | |
424 public: | |
425 StatelessDatabaseOperations(IDatabaseWrapper& database); | |
426 | |
427 void SetTransactionContextFactory(ITransactionContextFactory* factory /* takes ownership */); | |
428 | |
429 // It is assumed that "GetDatabaseVersion()" can run out of a | |
430 // database transaction | |
431 unsigned int GetDatabaseVersion() | |
432 { | |
433 return db_.GetDatabaseVersion(); | |
434 } | |
435 | |
436 void Apply(IReadOnlyOperations& operations); | |
437 | |
438 void Apply(IReadWriteOperations& operations); | |
439 | |
440 bool ExpandResource(Json::Value& target, | |
441 const std::string& publicId, | |
442 ResourceType level); | |
443 | |
444 void GetAllMetadata(std::map<MetadataType, std::string>& target, | |
445 const std::string& publicId, | |
446 ResourceType level); | |
447 | |
448 void GetAllUuids(std::list<std::string>& target, | |
449 ResourceType resourceType); | |
450 | |
451 void GetAllUuids(std::list<std::string>& target, | |
452 ResourceType resourceType, | |
453 size_t since, | |
454 size_t limit); | |
455 | |
456 void GetGlobalStatistics(/* out */ uint64_t& diskSize, | |
457 /* out */ uint64_t& uncompressedSize, | |
458 /* out */ uint64_t& countPatients, | |
459 /* out */ uint64_t& countStudies, | |
460 /* out */ uint64_t& countSeries, | |
461 /* out */ uint64_t& countInstances); | |
462 | |
463 bool LookupAttachment(FileInfo& attachment, | |
464 const std::string& instancePublicId, | |
465 FileContentType contentType); | |
466 | |
467 void GetChanges(Json::Value& target, | |
468 int64_t since, | |
469 unsigned int maxResults); | |
470 | |
471 void GetLastChange(Json::Value& target); | |
472 | |
473 void GetExportedResources(Json::Value& target, | |
474 int64_t since, | |
475 unsigned int maxResults); | |
476 | |
477 void GetLastExportedResource(Json::Value& target); | |
478 | |
479 bool IsProtectedPatient(const std::string& publicId); | |
480 | |
481 void GetChildren(std::list<std::string>& result, | |
482 const std::string& publicId); | |
483 | |
484 void GetChildInstances(std::list<std::string>& result, | |
485 const std::string& publicId); | |
486 | |
487 bool LookupMetadata(std::string& target, | |
488 const std::string& publicId, | |
489 ResourceType expectedType, | |
490 MetadataType type); | |
491 | |
492 void ListAvailableAttachments(std::set<FileContentType>& target, | |
493 const std::string& publicId, | |
494 ResourceType expectedType); | |
495 | |
496 bool LookupParent(std::string& target, | |
497 const std::string& publicId); | |
498 | |
499 void GetResourceStatistics(/* out */ ResourceType& type, | |
500 /* out */ uint64_t& diskSize, | |
501 /* out */ uint64_t& uncompressedSize, | |
502 /* out */ unsigned int& countStudies, | |
503 /* out */ unsigned int& countSeries, | |
504 /* out */ unsigned int& countInstances, | |
505 /* out */ uint64_t& dicomDiskSize, | |
506 /* out */ uint64_t& dicomUncompressedSize, | |
507 const std::string& publicId); | |
508 | |
509 void LookupIdentifierExact(std::vector<std::string>& result, | |
510 ResourceType level, | |
511 const DicomTag& tag, | |
512 const std::string& value); | |
513 | |
514 bool LookupGlobalProperty(std::string& value, | |
515 GlobalProperty property); | |
516 | |
517 std::string GetGlobalProperty(GlobalProperty property, | |
518 const std::string& defaultValue); | |
519 | |
520 bool GetMainDicomTags(DicomMap& result, | |
521 const std::string& publicId, | |
522 ResourceType expectedType, | |
523 ResourceType levelOfInterest); | |
524 | |
525 // Only applicable at the instance level | |
526 bool GetAllMainDicomTags(DicomMap& result, | |
527 const std::string& instancePublicId); | |
528 | |
529 bool LookupResourceType(ResourceType& type, | |
530 const std::string& publicId); | |
531 | |
532 bool LookupParent(std::string& target, | |
533 const std::string& publicId, | |
534 ResourceType parentType); | |
535 | |
536 void ApplyLookupResources(std::vector<std::string>& resourcesId, | |
537 std::vector<std::string>* instancesId, // Can be NULL if not needed | |
538 const DatabaseLookup& lookup, | |
539 ResourceType queryLevel, | |
540 size_t limit); | |
541 | |
542 bool DeleteResource(Json::Value& target /* out */, | |
543 const std::string& uuid, | |
544 ResourceType expectedType); | |
545 | |
546 void LogExportedResource(const std::string& publicId, | |
547 const std::string& remoteModality); | |
548 | |
549 void SetProtectedPatient(const std::string& publicId, | |
550 bool isProtected); | |
551 | |
552 void SetMetadata(const std::string& publicId, | |
553 MetadataType type, | |
554 const std::string& value); | |
555 | |
556 void DeleteMetadata(const std::string& publicId, | |
557 MetadataType type); | |
558 | |
559 uint64_t IncrementGlobalSequence(GlobalProperty sequence); | |
560 | |
561 void DeleteChanges(); | |
562 | |
563 void DeleteExportedResources(); | |
564 | |
565 void SetGlobalProperty(GlobalProperty property, | |
566 const std::string& value); | |
567 | |
568 void DeleteAttachment(const std::string& publicId, | |
569 FileContentType type); | |
570 | |
571 void LogChange(ChangeType changeType, | |
572 const std::string& publicId, | |
573 ResourceType level); | |
574 | |
575 void ReconstructInstance(const ParsedDicomFile& dicom); | |
576 | |
577 StoreStatus Store(std::map<MetadataType, std::string>& instanceMetadata, | |
578 const DicomMap& dicomSummary, | |
579 const Attachments& attachments, | |
580 const MetadataMap& metadata, | |
581 const DicomInstanceOrigin& origin, | |
582 bool overwrite, | |
583 bool hasTransferSyntax, | |
584 DicomTransferSyntax transferSyntax, | |
585 bool hasPixelDataOffset, | |
586 uint64_t pixelDataOffset, | |
587 uint64_t maximumStorageSize, | |
588 unsigned int maximumPatients); | |
589 | |
590 StoreStatus AddAttachment(const FileInfo& attachment, | |
591 const std::string& publicId, | |
592 uint64_t maximumStorageSize, | |
593 unsigned int maximumPatients); | |
594 }; | |
595 } |