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 }