Mercurial > hg > orthanc
annotate OrthancServer/Sources/ServerIndex.h @ 4574:855e43bb293c db-changes
cont
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 08 Mar 2021 18:15:26 +0100 |
parents | f6bd5563b5df |
children | a114a5db2afe |
rev | line source |
---|---|
0 | 1 /** |
62 | 2 * Orthanc - A Lightweight, RESTful DICOM Store |
1900 | 3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics |
1288
6e7e5ed91c2d
upgrade to year 2015
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1286
diff
changeset
|
4 * Department, University Hospital of Liege, Belgium |
4437
d9473bd5ed43
upgrade to year 2021
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4205
diff
changeset
|
5 * Copyright (C) 2017-2021 Osimis S.A., Belgium |
0 | 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. | |
136 | 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. | |
0 | 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 | |
4045 | 36 #include "../../OrthancFramework/Sources/Cache/LeastRecentlyUsedIndex.h" |
37 #include "../../OrthancFramework/Sources/DicomFormat/DicomMap.h" | |
3094
61da3c9b4121
cont reorganization
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3093
diff
changeset
|
38 |
61da3c9b4121
cont reorganization
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3093
diff
changeset
|
39 #include "Database/IDatabaseWrapper.h" |
4506
ac69c9f76c71
refactoring ServerIndex::Store()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4505
diff
changeset
|
40 #include "DicomInstanceOrigin.h" |
3094
61da3c9b4121
cont reorganization
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3093
diff
changeset
|
41 |
0 | 42 #include <boost/thread.hpp> |
220 | 43 #include <boost/noncopyable.hpp> |
186
f68c039b0571
preparing refactoring of ServerIndex
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
183
diff
changeset
|
44 |
62 | 45 namespace Orthanc |
0 | 46 { |
3094
61da3c9b4121
cont reorganization
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3093
diff
changeset
|
47 class DatabaseLookup; |
2209
e3fd5bc429a2
URI to reconstruct the main DICOM tags, the JSON summary and the metadata
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2188
diff
changeset
|
48 class ParsedDicomFile; |
3094
61da3c9b4121
cont reorganization
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3093
diff
changeset
|
49 class ServerContext; |
226
8a26a8e85edf
refactoring to read files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
224
diff
changeset
|
50 |
220 | 51 class ServerIndex : public boost::noncopyable |
0 | 52 { |
1002
b067017a8a5b
anonymization refactoring
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
739
diff
changeset
|
53 public: |
b067017a8a5b
anonymization refactoring
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
739
diff
changeset
|
54 typedef std::list<FileInfo> Attachments; |
2894
a27b0e9a3fd9
refactoring DicomInstanceToStore
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2825
diff
changeset
|
55 typedef std::map<std::pair<ResourceType, MetadataType>, std::string> MetadataMap; |
1002
b067017a8a5b
anonymization refactoring
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
739
diff
changeset
|
56 |
0 | 57 private: |
1432
0ac74fa21db8
rename IServerIndexListener as IDatabaseListener
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1364
diff
changeset
|
58 class Listener; |
278
771f12042be9
more efficient determination of storage size for recycling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
272
diff
changeset
|
59 class Transaction; |
1177
5b2d8c280ac2
Plugins can monitor changes through callbacks
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1162
diff
changeset
|
60 class UnstableResourcePayload; |
3027 | 61 class MainDicomTagsRegistry; |
278
771f12042be9
more efficient determination of storage size for recycling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
272
diff
changeset
|
62 |
511
3b735fdf320b
monitoring of stable patients/studies/series
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
440
diff
changeset
|
63 bool done_; |
0 | 64 boost::mutex mutex_; |
206
4453a010d0db
flush to disk thread
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
204
diff
changeset
|
65 boost::thread flushThread_; |
511
3b735fdf320b
monitoring of stable patients/studies/series
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
440
diff
changeset
|
66 boost::thread unstableResourcesMonitorThread_; |
0 | 67 |
3712
2a170a8f1faf
replacing std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3640
diff
changeset
|
68 std::unique_ptr<Listener> listener_; |
1247 | 69 IDatabaseWrapper& db_; |
511
3b735fdf320b
monitoring of stable patients/studies/series
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
440
diff
changeset
|
70 LeastRecentlyUsedIndex<int64_t, UnstableResourcePayload> unstableResources_; |
180
626777d01dc4
use of hashes to index dicom objects
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
179
diff
changeset
|
71 |
2825
8aa6aef11b70
New configuration option "OverwriteInstances" to choose how duplicate SOPInstanceUID are handled
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2668
diff
changeset
|
72 uint64_t maximumStorageSize_; |
269
f6fdf5abe751
recycling up and running
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
268
diff
changeset
|
73 unsigned int maximumPatients_; |
3712
2a170a8f1faf
replacing std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3640
diff
changeset
|
74 std::unique_ptr<MainDicomTagsRegistry> mainDicomTagsRegistry_; |
269
f6fdf5abe751
recycling up and running
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
268
diff
changeset
|
75 |
2665
389d050a2e66
fix deadlock, speed up unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2447
diff
changeset
|
76 static void FlushThread(ServerIndex* that, |
389d050a2e66
fix deadlock, speed up unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2447
diff
changeset
|
77 unsigned int threadSleep); |
511
3b735fdf320b
monitoring of stable patients/studies/series
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
440
diff
changeset
|
78 |
2665
389d050a2e66
fix deadlock, speed up unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2447
diff
changeset
|
79 static void UnstableResourcesMonitorThread(ServerIndex* that, |
389d050a2e66
fix deadlock, speed up unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2447
diff
changeset
|
80 unsigned int threadSleep); |
511
3b735fdf320b
monitoring of stable patients/studies/series
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
440
diff
changeset
|
81 |
4554 | 82 // A transaction must be running |
83 static void MainDicomTagsToJson(Json::Value& result, | |
84 IDatabaseWrapper& db, | |
85 int64_t resourceId, | |
86 ResourceType resourceType); | |
198
663cc6c46d0a
before refactoring of ServerIndex::GetXXX
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
197
diff
changeset
|
87 |
268
4bc02e2254ec
preparing ServerIndex for recycling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
238
diff
changeset
|
88 bool IsRecyclingNeeded(uint64_t instanceSize); |
4bc02e2254ec
preparing ServerIndex for recycling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
238
diff
changeset
|
89 |
4bc02e2254ec
preparing ServerIndex for recycling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
238
diff
changeset
|
90 void Recycle(uint64_t instanceSize, |
4bc02e2254ec
preparing ServerIndex for recycling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
238
diff
changeset
|
91 const std::string& newPatientId); |
4bc02e2254ec
preparing ServerIndex for recycling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
238
diff
changeset
|
92 |
269
f6fdf5abe751
recycling up and running
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
268
diff
changeset
|
93 void StandaloneRecycling(); |
f6fdf5abe751
recycling up and running
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
268
diff
changeset
|
94 |
511
3b735fdf320b
monitoring of stable patients/studies/series
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
440
diff
changeset
|
95 void MarkAsUnstable(int64_t id, |
1177
5b2d8c280ac2
Plugins can monitor changes through callbacks
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1162
diff
changeset
|
96 Orthanc::ResourceType type, |
5b2d8c280ac2
Plugins can monitor changes through callbacks
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1162
diff
changeset
|
97 const std::string& publicId); |
511
3b735fdf320b
monitoring of stable patients/studies/series
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
440
diff
changeset
|
98 |
1237 | 99 void LogChange(int64_t internalId, |
100 ChangeType changeType, | |
101 ResourceType resourceType, | |
1297 | 102 const std::string& publicId); |
1237 | 103 |
3029
ea653ec47f31
new class: DatabaseConstraint
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3027
diff
changeset
|
104 void NormalizeLookup(std::vector<DatabaseConstraint>& target, |
3027 | 105 const DatabaseLookup& source, |
106 ResourceType level) const; | |
107 | |
4554 | 108 // A transaction must be running |
109 static SeriesStatus GetSeriesStatus(IDatabaseWrapper& db, | |
110 int64_t id, | |
111 int64_t expectedNumberOfInstances); | |
112 | |
113 bool IsUnstableResource(int64_t id); | |
3090
31244604f617
starting optimization of SeriesIndex::GetSeriesStatus()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3086
diff
changeset
|
114 |
0 | 115 public: |
226
8a26a8e85edf
refactoring to read files
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
224
diff
changeset
|
116 ServerIndex(ServerContext& context, |
2665
389d050a2e66
fix deadlock, speed up unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2447
diff
changeset
|
117 IDatabaseWrapper& database, |
389d050a2e66
fix deadlock, speed up unit tests
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
2447
diff
changeset
|
118 unsigned int threadSleep); |
0 | 119 |
206
4453a010d0db
flush to disk thread
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
204
diff
changeset
|
120 ~ServerIndex(); |
4453a010d0db
flush to disk thread
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
204
diff
changeset
|
121 |
1453
c0bdc47165ef
code to warn about possible threading problems
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1432
diff
changeset
|
122 void Stop(); |
c0bdc47165ef
code to warn about possible threading problems
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1432
diff
changeset
|
123 |
269
f6fdf5abe751
recycling up and running
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
268
diff
changeset
|
124 uint64_t GetMaximumStorageSize() const |
f6fdf5abe751
recycling up and running
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
268
diff
changeset
|
125 { |
f6fdf5abe751
recycling up and running
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
268
diff
changeset
|
126 return maximumStorageSize_; |
f6fdf5abe751
recycling up and running
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
268
diff
changeset
|
127 } |
f6fdf5abe751
recycling up and running
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
268
diff
changeset
|
128 |
f6fdf5abe751
recycling up and running
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
268
diff
changeset
|
129 uint64_t GetMaximumPatientCount() const |
f6fdf5abe751
recycling up and running
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
268
diff
changeset
|
130 { |
f6fdf5abe751
recycling up and running
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
268
diff
changeset
|
131 return maximumPatients_; |
f6fdf5abe751
recycling up and running
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
268
diff
changeset
|
132 } |
f6fdf5abe751
recycling up and running
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
268
diff
changeset
|
133 |
f6fdf5abe751
recycling up and running
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
268
diff
changeset
|
134 // "size == 0" means no limit on the storage size |
f6fdf5abe751
recycling up and running
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
268
diff
changeset
|
135 void SetMaximumStorageSize(uint64_t size); |
f6fdf5abe751
recycling up and running
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
268
diff
changeset
|
136 |
f6fdf5abe751
recycling up and running
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
268
diff
changeset
|
137 // "count == 0" means no limit on the number of patients |
f6fdf5abe751
recycling up and running
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
268
diff
changeset
|
138 void SetMaximumPatientCount(unsigned int count); |
f6fdf5abe751
recycling up and running
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
268
diff
changeset
|
139 |
1006
649d47854314
proper handling of metadata in Store
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
1004
diff
changeset
|
140 StoreStatus Store(std::map<MetadataType, std::string>& instanceMetadata, |
4505
97d103b57cd1
removed cached dicom summary from DicomInstanceToStore
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4499
diff
changeset
|
141 const DicomMap& dicomSummary, |
3813
aaaa442bfe39
moving SetOverwriteInstances from ServerIndex to ServerContext
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
3712
diff
changeset
|
142 const Attachments& attachments, |
4506
ac69c9f76c71
refactoring ServerIndex::Store()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4505
diff
changeset
|
143 const MetadataMap& metadata, |
ac69c9f76c71
refactoring ServerIndex::Store()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4505
diff
changeset
|
144 const DicomInstanceOrigin& origin, |
4499 | 145 bool overwrite, |
4506
ac69c9f76c71
refactoring ServerIndex::Store()
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4505
diff
changeset
|
146 bool hasTransferSyntax, |
4507
b4c58795f3a8
widening the use of DicomTransferSyntax enum
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4506
diff
changeset
|
147 DicomTransferSyntax transferSyntax, |
4499 | 148 bool hasPixelDataOffset, |
149 uint64_t pixelDataOffset); | |
0 | 150 |
699
2929e17f8447
add attachments to resources
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
697
diff
changeset
|
151 StoreStatus AddAttachment(const FileInfo& attachment, |
2929e17f8447
add attachments to resources
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
697
diff
changeset
|
152 const std::string& publicId); |
2929e17f8447
add attachments to resources
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
697
diff
changeset
|
153 |
4551
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
154 |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
155 |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
156 /*** |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
157 ** PROTOTYPING FOR DB REFACTORING BELOW |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
158 ***/ |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
159 |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
160 public: |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
161 class ReadOnlyTransaction : public boost::noncopyable |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
162 { |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
163 protected: |
4554 | 164 IDatabaseWrapper& db_; |
4551
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
165 |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
166 public: |
4555 | 167 explicit ReadOnlyTransaction(IDatabaseWrapper& db) : |
4554 | 168 db_(db) |
169 { | |
170 } | |
171 | |
172 /** | |
173 * Higher-level constructions | |
174 **/ | |
175 | |
176 SeriesStatus GetSeriesStatus(int64_t id, | |
177 int64_t expectedNumberOfInstances) | |
178 { | |
179 return ServerIndex::GetSeriesStatus(db_, id, expectedNumberOfInstances); | |
180 } | |
181 | |
182 void MainDicomTagsToJson(Json::Value& result, | |
183 int64_t resourceId, | |
184 ResourceType resourceType) | |
4551
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
185 { |
4554 | 186 ServerIndex::MainDicomTagsToJson(result, db_, resourceId, resourceType); |
187 } | |
188 | |
189 /** | |
190 * Read-only methods from "IDatabaseWrapper" | |
191 **/ | |
192 | |
4562 | 193 void ApplyLookupResources(std::list<std::string>& resourcesId, |
194 std::list<std::string>* instancesId, // Can be NULL if not needed | |
195 const std::vector<DatabaseConstraint>& lookup, | |
196 ResourceType queryLevel, | |
197 size_t limit) | |
198 { | |
199 return db_.ApplyLookupResources(resourcesId, instancesId, lookup, queryLevel, limit); | |
200 } | |
201 | |
4554 | 202 void GetAllMetadata(std::map<MetadataType, std::string>& target, |
203 int64_t id) | |
204 { | |
205 db_.GetAllMetadata(target, id); | |
4555 | 206 } |
207 | |
208 void GetAllPublicIds(std::list<std::string>& target, | |
209 ResourceType resourceType) | |
210 { | |
211 return db_.GetAllPublicIds(target, resourceType); | |
212 } | |
213 | |
214 void GetAllPublicIds(std::list<std::string>& target, | |
215 ResourceType resourceType, | |
216 size_t since, | |
217 size_t limit) | |
218 { | |
219 return db_.GetAllPublicIds(target, resourceType, since, limit); | |
220 } | |
4554 | 221 |
4558 | 222 void GetChanges(std::list<ServerIndexChange>& target /*out*/, |
223 bool& done /*out*/, | |
224 int64_t since, | |
225 uint32_t maxResults) | |
226 { | |
227 db_.GetChanges(target, done, since, maxResults); | |
228 } | |
229 | |
4559 | 230 void GetChildrenInternalId(std::list<int64_t>& target, |
231 int64_t id) | |
232 { | |
233 db_.GetChildrenInternalId(target, id); | |
234 } | |
235 | |
4554 | 236 void GetChildrenPublicId(std::list<std::string>& target, |
237 int64_t id) | |
238 { | |
239 db_.GetChildrenPublicId(target, id); | |
240 } | |
241 | |
4563
bb1c365f9e44
end of refactoring read-only transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4562
diff
changeset
|
242 unsigned int GetDatabaseVersion() |
bb1c365f9e44
end of refactoring read-only transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4562
diff
changeset
|
243 { |
bb1c365f9e44
end of refactoring read-only transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4562
diff
changeset
|
244 return db_.GetDatabaseVersion(); |
bb1c365f9e44
end of refactoring read-only transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4562
diff
changeset
|
245 } |
bb1c365f9e44
end of refactoring read-only transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4562
diff
changeset
|
246 |
4558 | 247 void GetExportedResources(std::list<ExportedResource>& target /*out*/, |
248 bool& done /*out*/, | |
249 int64_t since, | |
250 uint32_t maxResults) | |
251 { | |
252 return db_.GetExportedResources(target, done, since, maxResults); | |
253 } | |
254 | |
255 void GetLastChange(std::list<ServerIndexChange>& target /*out*/) | |
256 { | |
257 db_.GetLastChange(target); | |
258 } | |
259 | |
260 void GetLastExportedResource(std::list<ExportedResource>& target /*out*/) | |
261 { | |
262 return db_.GetLastExportedResource(target); | |
263 } | |
264 | |
265 int64_t GetLastChangeIndex() | |
266 { | |
267 return db_.GetLastChangeIndex(); | |
268 } | |
269 | |
4554 | 270 void GetMainDicomTags(DicomMap& map, |
271 int64_t id) | |
272 { | |
273 db_.GetMainDicomTags(map, id); | |
4551
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
274 } |
4558 | 275 |
4559 | 276 std::string GetPublicId(int64_t resourceId) |
277 { | |
278 return db_.GetPublicId(resourceId); | |
279 } | |
280 | |
4558 | 281 uint64_t GetResourceCount(ResourceType resourceType) |
282 { | |
283 return db_.GetResourceCount(resourceType); | |
284 } | |
285 | |
4559 | 286 ResourceType GetResourceType(int64_t resourceId) |
287 { | |
288 return db_.GetResourceType(resourceId); | |
289 } | |
290 | |
4558 | 291 uint64_t GetTotalCompressedSize() |
292 { | |
293 return db_.GetTotalCompressedSize(); | |
294 } | |
295 | |
296 uint64_t GetTotalUncompressedSize() | |
297 { | |
298 return db_.GetTotalUncompressedSize(); | |
299 } | |
4551
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
300 |
4559 | 301 bool IsProtectedPatient(int64_t internalId) |
302 { | |
303 return db_.IsProtectedPatient(internalId); | |
304 } | |
305 | |
4560 | 306 void ListAvailableAttachments(std::set<FileContentType>& target, |
307 int64_t id) | |
308 { | |
309 db_.ListAvailableAttachments(target, id); | |
310 } | |
311 | |
4554 | 312 bool LookupAttachment(FileInfo& attachment, |
313 int64_t id, | |
314 FileContentType contentType) | |
4551
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
315 { |
4554 | 316 return db_.LookupAttachment(attachment, id, contentType); |
4551
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
317 } |
4554 | 318 |
4562 | 319 bool LookupGlobalProperty(std::string& target, |
320 GlobalProperty property) | |
321 { | |
322 return db_.LookupGlobalProperty(target, property); | |
323 } | |
324 | |
4560 | 325 bool LookupMetadata(std::string& target, |
326 int64_t id, | |
327 MetadataType type) | |
328 { | |
329 return db_.LookupMetadata(target, id, type); | |
330 } | |
331 | |
332 bool LookupParent(int64_t& parentId, | |
333 int64_t resourceId) | |
334 { | |
335 return db_.LookupParent(parentId, resourceId); | |
336 } | |
337 | |
4554 | 338 bool LookupResource(int64_t& id, |
339 ResourceType& type, | |
340 const std::string& publicId) | |
4551
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
341 { |
4554 | 342 return db_.LookupResource(id, type, publicId); |
343 } | |
344 | |
345 bool LookupResourceAndParent(int64_t& id, | |
346 ResourceType& type, | |
347 std::string& parentPublicId, | |
348 const std::string& publicId) | |
349 { | |
350 return db_.LookupResourceAndParent(id, type, parentPublicId, publicId); | |
4551
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
351 } |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
352 }; |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
353 |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
354 |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
355 class ReadWriteTransaction : public ReadOnlyTransaction |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
356 { |
4567 | 357 private: |
4573 | 358 Listener& listener_; |
359 ServerIndex& index_; // TODO - REMOVE | |
4567 | 360 |
4551
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
361 public: |
4567 | 362 ReadWriteTransaction(IDatabaseWrapper& db, |
4573 | 363 Listener& listener, |
4567 | 364 ServerIndex& index) : |
365 ReadOnlyTransaction(db), | |
4573 | 366 listener_(listener), |
367 index_(index) | |
4567 | 368 { |
369 } | |
370 | |
4573 | 371 Listener& GetListener() |
372 { | |
373 return listener_; | |
374 } | |
375 | |
4567 | 376 void ClearChanges() |
4551
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
377 { |
4567 | 378 db_.ClearChanges(); |
379 } | |
380 | |
381 void ClearExportedResources() | |
382 { | |
383 db_.ClearExportedResources(); | |
384 } | |
385 | |
4574 | 386 void ClearMainDicomTags(int64_t id) |
387 { | |
388 return db_.ClearMainDicomTags(id); | |
389 } | |
390 | |
4568 | 391 void DeleteAttachment(int64_t id, |
392 FileContentType attachment) | |
393 { | |
394 return db_.DeleteAttachment(id, attachment); | |
395 } | |
396 | |
4567 | 397 void DeleteMetadata(int64_t id, |
398 MetadataType type) | |
399 { | |
400 db_.DeleteMetadata(id, type); | |
4551
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
401 } |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
402 |
4565
3495a3d97ab6
start of read-write transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4563
diff
changeset
|
403 void DeleteResource(int64_t id) |
3495a3d97ab6
start of read-write transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4563
diff
changeset
|
404 { |
3495a3d97ab6
start of read-write transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4563
diff
changeset
|
405 db_.DeleteResource(id); |
3495a3d97ab6
start of read-write transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4563
diff
changeset
|
406 } |
3495a3d97ab6
start of read-write transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4563
diff
changeset
|
407 |
4567 | 408 void LogChange(int64_t internalId, |
409 ChangeType changeType, | |
410 ResourceType resourceType, | |
411 const std::string& publicId) | |
412 { | |
413 index_.LogChange(internalId, changeType, resourceType, publicId); | |
414 } | |
415 | |
4565
3495a3d97ab6
start of read-write transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4563
diff
changeset
|
416 void LogExportedResource(const ExportedResource& resource) |
3495a3d97ab6
start of read-write transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4563
diff
changeset
|
417 { |
3495a3d97ab6
start of read-write transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4563
diff
changeset
|
418 db_.LogExportedResource(resource); |
3495a3d97ab6
start of read-write transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4563
diff
changeset
|
419 } |
4567 | 420 |
421 void SetGlobalProperty(GlobalProperty property, | |
422 const std::string& value) | |
423 { | |
424 db_.SetGlobalProperty(property, value); | |
425 } | |
426 | |
427 void SetMetadata(int64_t id, | |
428 MetadataType type, | |
429 const std::string& value) | |
430 { | |
431 return db_.SetMetadata(id, type, value); | |
432 } | |
433 | |
434 void SetProtectedPatient(int64_t internalId, | |
435 bool isProtected) | |
436 { | |
437 db_.SetProtectedPatient(internalId, isProtected); | |
438 } | |
4574 | 439 |
440 void SetResourcesContent(const ResourcesContent& content) | |
441 { | |
442 db_.SetResourcesContent(content); | |
443 } | |
4551
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
444 }; |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
445 |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
446 |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
447 class IReadOnlyOperations : public boost::noncopyable |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
448 { |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
449 public: |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
450 virtual ~IReadOnlyOperations() |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
451 { |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
452 } |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
453 |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
454 virtual void Apply(ReadOnlyTransaction& transaction) = 0; |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
455 }; |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
456 |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
457 |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
458 class IReadWriteOperations : public boost::noncopyable |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
459 { |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
460 public: |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
461 virtual ~IReadWriteOperations() |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
462 { |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
463 } |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
464 |
4573 | 465 virtual void Apply(ReadWriteTransaction& transaction) = 0; |
4551
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
466 }; |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
467 |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
468 private: |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
469 void ApplyInternal(IReadOnlyOperations* readOperations, |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
470 IReadWriteOperations* writeOperations); |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
471 |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
472 unsigned int maxRetries_; |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
473 |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
474 public: |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
475 void Apply(IReadOnlyOperations& operations); |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
476 |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
477 void Apply(IReadWriteOperations& operations); |
350a22c094f2
testing replay of transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4514
diff
changeset
|
478 |
4554 | 479 bool ExpandResource(Json::Value& target, |
480 const std::string& publicId, | |
481 ResourceType level); | |
482 | |
483 void GetAllMetadata(std::map<MetadataType, std::string>& target, | |
484 const std::string& publicId, | |
485 ResourceType level); | |
4555 | 486 |
487 void GetAllUuids(std::list<std::string>& target, | |
488 ResourceType resourceType); | |
489 | |
490 void GetAllUuids(std::list<std::string>& target, | |
491 ResourceType resourceType, | |
492 size_t since, | |
493 size_t limit); | |
494 | |
4558 | 495 void GetGlobalStatistics(/* out */ uint64_t& diskSize, |
496 /* out */ uint64_t& uncompressedSize, | |
497 /* out */ uint64_t& countPatients, | |
498 /* out */ uint64_t& countStudies, | |
499 /* out */ uint64_t& countSeries, | |
500 /* out */ uint64_t& countInstances); | |
501 | |
4555 | 502 bool LookupAttachment(FileInfo& attachment, |
503 const std::string& instancePublicId, | |
504 FileContentType contentType); | |
4558 | 505 |
506 void GetChanges(Json::Value& target, | |
507 int64_t since, | |
508 unsigned int maxResults); | |
509 | |
510 void GetLastChange(Json::Value& target); | |
511 | |
512 void GetExportedResources(Json::Value& target, | |
513 int64_t since, | |
514 unsigned int maxResults); | |
515 | |
516 void GetLastExportedResource(Json::Value& target); | |
517 | |
4559 | 518 bool IsProtectedPatient(const std::string& publicId); |
519 | |
520 void GetChildren(std::list<std::string>& result, | |
521 const std::string& publicId); | |
522 | |
523 void GetChildInstances(std::list<std::string>& result, | |
524 const std::string& publicId); | |
4560 | 525 |
526 bool LookupMetadata(std::string& target, | |
527 const std::string& publicId, | |
528 ResourceType expectedType, | |
529 MetadataType type); | |
530 | |
531 void ListAvailableAttachments(std::set<FileContentType>& target, | |
532 const std::string& publicId, | |
533 ResourceType expectedType); | |
534 | |
535 bool LookupParent(std::string& target, | |
536 const std::string& publicId); | |
4562 | 537 |
538 void GetResourceStatistics(/* out */ ResourceType& type, | |
539 /* out */ uint64_t& diskSize, | |
540 /* out */ uint64_t& uncompressedSize, | |
541 /* out */ unsigned int& countStudies, | |
542 /* out */ unsigned int& countSeries, | |
543 /* out */ unsigned int& countInstances, | |
544 /* out */ uint64_t& dicomDiskSize, | |
545 /* out */ uint64_t& dicomUncompressedSize, | |
546 const std::string& publicId); | |
547 | |
548 void LookupIdentifierExact(std::vector<std::string>& result, | |
549 ResourceType level, | |
550 const DicomTag& tag, | |
551 const std::string& value); | |
552 | |
553 bool LookupGlobalProperty(std::string& value, | |
554 GlobalProperty property); | |
555 | |
556 std::string GetGlobalProperty(GlobalProperty property, | |
557 const std::string& defaultValue); | |
558 | |
559 bool GetMainDicomTags(DicomMap& result, | |
560 const std::string& publicId, | |
561 ResourceType expectedType, | |
562 ResourceType levelOfInterest); | |
4563
bb1c365f9e44
end of refactoring read-only transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4562
diff
changeset
|
563 |
bb1c365f9e44
end of refactoring read-only transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4562
diff
changeset
|
564 // Only applicable at the instance level |
bb1c365f9e44
end of refactoring read-only transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4562
diff
changeset
|
565 bool GetAllMainDicomTags(DicomMap& result, |
bb1c365f9e44
end of refactoring read-only transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4562
diff
changeset
|
566 const std::string& instancePublicId); |
bb1c365f9e44
end of refactoring read-only transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4562
diff
changeset
|
567 |
bb1c365f9e44
end of refactoring read-only transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4562
diff
changeset
|
568 bool LookupResourceType(ResourceType& type, |
bb1c365f9e44
end of refactoring read-only transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4562
diff
changeset
|
569 const std::string& publicId); |
bb1c365f9e44
end of refactoring read-only transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4562
diff
changeset
|
570 |
bb1c365f9e44
end of refactoring read-only transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4562
diff
changeset
|
571 unsigned int GetDatabaseVersion(); |
bb1c365f9e44
end of refactoring read-only transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4562
diff
changeset
|
572 |
bb1c365f9e44
end of refactoring read-only transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4562
diff
changeset
|
573 bool LookupParent(std::string& target, |
bb1c365f9e44
end of refactoring read-only transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4562
diff
changeset
|
574 const std::string& publicId, |
bb1c365f9e44
end of refactoring read-only transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4562
diff
changeset
|
575 ResourceType parentType); |
bb1c365f9e44
end of refactoring read-only transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4562
diff
changeset
|
576 |
bb1c365f9e44
end of refactoring read-only transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4562
diff
changeset
|
577 void ApplyLookupResources(std::vector<std::string>& resourcesId, |
bb1c365f9e44
end of refactoring read-only transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4562
diff
changeset
|
578 std::vector<std::string>* instancesId, // Can be NULL if not needed |
bb1c365f9e44
end of refactoring read-only transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4562
diff
changeset
|
579 const DatabaseLookup& lookup, |
bb1c365f9e44
end of refactoring read-only transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4562
diff
changeset
|
580 ResourceType queryLevel, |
bb1c365f9e44
end of refactoring read-only transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4562
diff
changeset
|
581 size_t limit); |
4565
3495a3d97ab6
start of read-write transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4563
diff
changeset
|
582 |
3495a3d97ab6
start of read-write transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4563
diff
changeset
|
583 bool DeleteResource(Json::Value& target /* out */, |
3495a3d97ab6
start of read-write transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4563
diff
changeset
|
584 const std::string& uuid, |
3495a3d97ab6
start of read-write transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4563
diff
changeset
|
585 ResourceType expectedType); |
3495a3d97ab6
start of read-write transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4563
diff
changeset
|
586 |
3495a3d97ab6
start of read-write transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4563
diff
changeset
|
587 void LogExportedResource(const std::string& publicId, |
3495a3d97ab6
start of read-write transactions
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
4563
diff
changeset
|
588 const std::string& remoteModality); |
4567 | 589 |
590 void SetProtectedPatient(const std::string& publicId, | |
591 bool isProtected); | |
592 | |
593 void SetMetadata(const std::string& publicId, | |
594 MetadataType type, | |
595 const std::string& value); | |
596 | |
597 void DeleteMetadata(const std::string& publicId, | |
598 MetadataType type); | |
599 | |
600 uint64_t IncrementGlobalSequence(GlobalProperty sequence); | |
601 | |
602 void DeleteChanges(); | |
603 | |
604 void DeleteExportedResources(); | |
605 | |
606 void SetGlobalProperty(GlobalProperty property, | |
607 const std::string& value); | |
4568 | 608 |
609 void DeleteAttachment(const std::string& publicId, | |
610 FileContentType type); | |
611 | |
612 void LogChange(ChangeType changeType, | |
613 const std::string& publicId); | |
4574 | 614 |
615 void ReconstructInstance(const ParsedDicomFile& dicom); | |
0 | 616 }; |
617 } |