Mercurial > hg > orthanc-webviewer
annotate Plugin/Cache/CacheManager.cpp @ 320:553fa466835a
updated copyright, as Orthanc Team now replaces Osimis
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 30 May 2024 22:04:03 +0200 |
parents | 591ca447ebf8 |
children |
rev | line source |
---|---|
0 | 1 /** |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
122 | 3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics |
0 | 4 * Department, University Hospital of Liege, Belgium |
320
553fa466835a
updated copyright, as Orthanc Team now replaces Osimis
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
316
diff
changeset
|
5 * Copyright (C) 2017-2023 Osimis S.A., Belgium |
553fa466835a
updated copyright, as Orthanc Team now replaces Osimis
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
316
diff
changeset
|
6 * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium |
314
0a1ad7492050
update year to 2024
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
303
diff
changeset
|
7 * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium |
0 | 8 * |
9 * This program is free software: you can redistribute it and/or | |
10 * modify it under the terms of the GNU Affero General Public License | |
11 * as published by the Free Software Foundation, either version 3 of | |
12 * the License, or (at your option) any later version. | |
13 * | |
14 * This program is distributed in the hope that it will be useful, but | |
15 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 * Affero General Public License for more details. | |
18 * | |
19 * You should have received a copy of the GNU Affero General Public License | |
20 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
21 **/ | |
22 | |
23 | |
24 #include "CacheManager.h" | |
25 | |
266
4e9d30c19b4b
linking against orthanc framework library
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
226
diff
changeset
|
26 #include <Compatibility.h> |
4e9d30c19b4b
linking against orthanc framework library
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
226
diff
changeset
|
27 #include <Toolbox.h> |
4e9d30c19b4b
linking against orthanc framework library
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
226
diff
changeset
|
28 #include <SQLite/Transaction.h> |
0 | 29 |
30 #include <boost/lexical_cast.hpp> | |
31 | |
32 | |
33 namespace OrthancPlugins | |
34 { | |
35 class CacheManager::Bundle | |
36 { | |
37 private: | |
38 uint32_t count_; | |
39 uint64_t space_; | |
40 | |
41 public: | |
42 Bundle() : count_(0), space_(0) | |
43 { | |
44 } | |
45 | |
46 Bundle(uint32_t count, | |
47 uint64_t space) : | |
48 count_(count), space_(space) | |
49 { | |
50 } | |
51 | |
52 uint32_t GetCount() const | |
53 { | |
54 return count_; | |
55 } | |
56 | |
57 uint64_t GetSpace() const | |
58 { | |
59 return space_; | |
60 } | |
61 | |
62 void Remove(uint64_t fileSize) | |
63 { | |
64 if (count_ == 0 || | |
65 space_ < fileSize) | |
66 { | |
67 throw std::runtime_error("Internal error"); | |
68 } | |
69 | |
70 count_ -= 1; | |
71 space_ -= fileSize; | |
72 } | |
73 | |
74 void Add(uint64_t fileSize) | |
75 { | |
76 count_ += 1; | |
77 space_ += fileSize; | |
78 } | |
79 }; | |
80 | |
81 | |
82 class CacheManager::BundleQuota | |
83 { | |
84 private: | |
85 uint32_t maxCount_; | |
86 uint64_t maxSpace_; | |
87 | |
88 public: | |
89 BundleQuota(uint32_t maxCount, | |
90 uint64_t maxSpace) : | |
91 maxCount_(maxCount), maxSpace_(maxSpace) | |
92 { | |
93 } | |
94 | |
95 BundleQuota() | |
96 { | |
97 // Default quota | |
98 maxCount_ = 0; // No limit on the number of files | |
99 maxSpace_ = 100 * 1024 * 1024; // Max 100MB per bundle | |
100 } | |
101 | |
102 uint32_t GetMaxCount() const | |
103 { | |
104 return maxCount_; | |
105 } | |
106 | |
107 uint64_t GetMaxSpace() const | |
108 { | |
109 return maxSpace_; | |
110 } | |
111 | |
112 bool IsSatisfied(const Bundle& bundle) const | |
113 { | |
114 if (maxCount_ != 0 && | |
115 bundle.GetCount() > maxCount_) | |
116 { | |
117 return false; | |
118 } | |
119 | |
120 if (maxSpace_ != 0 && | |
121 bundle.GetSpace() > maxSpace_) | |
122 { | |
123 return false; | |
124 } | |
125 | |
126 return true; | |
127 } | |
128 }; | |
129 | |
130 | |
131 struct CacheManager::PImpl | |
132 { | |
147
70d1fe6d6309
Avoid hard crash if not enough memory
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
122
diff
changeset
|
133 OrthancPluginContext* context_; |
0 | 134 Orthanc::SQLite::Connection& db_; |
135 Orthanc::FilesystemStorage& storage_; | |
136 | |
137 bool sanityCheck_; | |
138 Bundles bundles_; | |
139 BundleQuota defaultQuota_; | |
140 BundleQuotas quotas_; | |
141 | |
147
70d1fe6d6309
Avoid hard crash if not enough memory
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
122
diff
changeset
|
142 PImpl(OrthancPluginContext* context, |
70d1fe6d6309
Avoid hard crash if not enough memory
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
122
diff
changeset
|
143 Orthanc::SQLite::Connection& db, |
0 | 144 Orthanc::FilesystemStorage& storage) : |
147
70d1fe6d6309
Avoid hard crash if not enough memory
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
122
diff
changeset
|
145 context_(context), |
0 | 146 db_(db), |
147 storage_(storage), | |
148 sanityCheck_(false) | |
149 { | |
150 } | |
151 }; | |
152 | |
153 | |
154 const CacheManager::BundleQuota& CacheManager::GetBundleQuota(int bundleIndex) const | |
155 { | |
156 BundleQuotas::const_iterator found = pimpl_->quotas_.find(bundleIndex); | |
157 | |
158 if (found == pimpl_->quotas_.end()) | |
159 { | |
160 return pimpl_->defaultQuota_; | |
161 } | |
162 else | |
163 { | |
164 return found->second; | |
165 } | |
166 } | |
167 | |
168 | |
169 CacheManager::Bundle CacheManager::GetBundle(int bundleIndex) const | |
170 { | |
171 Bundles::const_iterator it = pimpl_->bundles_.find(bundleIndex); | |
172 | |
173 if (it == pimpl_->bundles_.end()) | |
174 { | |
175 return Bundle(); | |
176 } | |
177 else | |
178 { | |
179 return it->second; | |
180 } | |
181 } | |
182 | |
183 | |
184 void CacheManager::MakeRoom(Bundle& bundle, | |
185 std::list<std::string>& toRemove, | |
186 int bundleIndex, | |
187 const BundleQuota& quota) | |
188 { | |
189 toRemove.clear(); | |
190 | |
191 // Make room in the bundle | |
192 while (!quota.IsSatisfied(bundle)) | |
193 { | |
296
d179f3928342
removed "using namespace Orthanc"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
295
diff
changeset
|
194 Orthanc::SQLite::Statement s(pimpl_->db_, SQLITE_FROM_HERE, "SELECT seq, fileUuid, fileSize FROM Cache WHERE bundle=? ORDER BY seq"); |
0 | 195 s.BindInt(0, bundleIndex); |
196 | |
197 if (s.Step()) | |
198 { | |
296
d179f3928342
removed "using namespace Orthanc"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
295
diff
changeset
|
199 Orthanc::SQLite::Statement t(pimpl_->db_, SQLITE_FROM_HERE, "DELETE FROM Cache WHERE seq=?"); |
0 | 200 t.BindInt64(0, s.ColumnInt64(0)); |
201 t.Run(); | |
202 | |
203 toRemove.push_back(s.ColumnString(1)); | |
204 bundle.Remove(s.ColumnInt64(2)); | |
205 } | |
206 else | |
207 { | |
208 // Should never happen | |
209 throw std::runtime_error("Internal error"); | |
210 } | |
211 } | |
212 } | |
213 | |
214 | |
215 | |
216 void CacheManager::EnsureQuota(int bundleIndex, | |
217 const BundleQuota& quota) | |
218 { | |
219 // Remove the cached files that exceed the quota | |
296
d179f3928342
removed "using namespace Orthanc"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
295
diff
changeset
|
220 std::unique_ptr<Orthanc::SQLite::Transaction> transaction(new Orthanc::SQLite::Transaction(pimpl_->db_)); |
0 | 221 transaction->Begin(); |
222 | |
223 Bundle bundle = GetBundle(bundleIndex); | |
224 | |
225 std::list<std::string> toRemove; | |
226 MakeRoom(bundle, toRemove, bundleIndex, quota); | |
227 | |
228 transaction->Commit(); | |
229 for (std::list<std::string>::const_iterator | |
197 | 230 it = toRemove.begin(); it != toRemove.end(); ++it) |
0 | 231 { |
23
7a0af291cc90
Synchronization with Orthanc mainline
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
232 pimpl_->storage_.Remove(*it, Orthanc::FileContentType_Unknown); |
0 | 233 } |
234 | |
235 pimpl_->bundles_[bundleIndex] = bundle; | |
236 } | |
237 | |
238 | |
239 | |
240 void CacheManager::ReadBundleStatistics() | |
241 { | |
242 pimpl_->bundles_.clear(); | |
243 | |
296
d179f3928342
removed "using namespace Orthanc"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
295
diff
changeset
|
244 Orthanc::SQLite::Statement s(pimpl_->db_, SQLITE_FROM_HERE, "SELECT bundle,COUNT(*),SUM(fileSize) FROM Cache GROUP BY bundle"); |
0 | 245 while (s.Step()) |
246 { | |
247 int index = s.ColumnInt(0); | |
248 Bundle bundle(static_cast<uint32_t>(s.ColumnInt(1)), | |
249 static_cast<uint64_t>(s.ColumnInt64(2))); | |
250 pimpl_->bundles_[index] = bundle; | |
251 } | |
252 } | |
253 | |
254 | |
255 | |
256 void CacheManager::SanityCheck() | |
257 { | |
258 if (!pimpl_->sanityCheck_) | |
259 { | |
260 return; | |
261 } | |
262 | |
296
d179f3928342
removed "using namespace Orthanc"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
295
diff
changeset
|
263 Orthanc::SQLite::Statement s(pimpl_->db_, SQLITE_FROM_HERE, "SELECT bundle,COUNT(*),SUM(fileSize) FROM Cache GROUP BY bundle"); |
0 | 264 while (s.Step()) |
265 { | |
266 const Bundle& bundle = GetBundle(s.ColumnInt(0)); | |
267 if (bundle.GetCount() != static_cast<uint32_t>(s.ColumnInt(1)) || | |
268 bundle.GetSpace() != static_cast<uint64_t>(s.ColumnInt64(2))) | |
269 { | |
270 throw std::runtime_error("SANITY ERROR in cache: " + boost::lexical_cast<std::string>(bundle.GetCount()) | |
271 + "/" + boost::lexical_cast<std::string>(bundle.GetSpace()) | |
272 + " vs " + boost::lexical_cast<std::string>(s.ColumnInt(1)) + "/" | |
273 + boost::lexical_cast<std::string>(s.ColumnInt64(2))); | |
274 } | |
275 } | |
276 } | |
277 | |
278 | |
279 | |
147
70d1fe6d6309
Avoid hard crash if not enough memory
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
122
diff
changeset
|
280 CacheManager::CacheManager(OrthancPluginContext* context, |
70d1fe6d6309
Avoid hard crash if not enough memory
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
122
diff
changeset
|
281 Orthanc::SQLite::Connection& db, |
0 | 282 Orthanc::FilesystemStorage& storage) : |
147
70d1fe6d6309
Avoid hard crash if not enough memory
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
122
diff
changeset
|
283 pimpl_(new PImpl(context, db, storage)) |
0 | 284 { |
285 Open(); | |
286 ReadBundleStatistics(); | |
287 } | |
288 | |
289 | |
147
70d1fe6d6309
Avoid hard crash if not enough memory
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
122
diff
changeset
|
290 OrthancPluginContext* CacheManager::GetPluginContext() const |
70d1fe6d6309
Avoid hard crash if not enough memory
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
122
diff
changeset
|
291 { |
70d1fe6d6309
Avoid hard crash if not enough memory
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
122
diff
changeset
|
292 return pimpl_->context_; |
70d1fe6d6309
Avoid hard crash if not enough memory
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
122
diff
changeset
|
293 } |
70d1fe6d6309
Avoid hard crash if not enough memory
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
122
diff
changeset
|
294 |
70d1fe6d6309
Avoid hard crash if not enough memory
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
122
diff
changeset
|
295 |
0 | 296 void CacheManager::SetSanityCheckEnabled(bool enabled) |
297 { | |
298 pimpl_->sanityCheck_ = enabled; | |
299 } | |
300 | |
301 | |
302 void CacheManager::Open() | |
303 { | |
304 if (!pimpl_->db_.DoesTableExist("Cache")) | |
305 { | |
306 pimpl_->db_.Execute("CREATE TABLE Cache(seq INTEGER PRIMARY KEY, bundle INTEGER, item TEXT, fileUuid TEXT, fileSize INT);"); | |
307 pimpl_->db_.Execute("CREATE INDEX CacheBundles ON Cache(bundle);"); | |
308 pimpl_->db_.Execute("CREATE INDEX CacheIndex ON Cache(bundle, item);"); | |
309 } | |
310 | |
115
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
311 if (!pimpl_->db_.DoesTableExist("CacheProperties")) |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
312 { |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
313 pimpl_->db_.Execute("CREATE TABLE CacheProperties(property INTEGER PRIMARY KEY, value TEXT);"); |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
314 } |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
315 |
0 | 316 // Performance tuning of SQLite with PRAGMAs |
317 // http://www.sqlite.org/pragma.html | |
318 pimpl_->db_.Execute("PRAGMA SYNCHRONOUS=OFF;"); | |
319 pimpl_->db_.Execute("PRAGMA JOURNAL_MODE=WAL;"); | |
320 pimpl_->db_.Execute("PRAGMA LOCKING_MODE=EXCLUSIVE;"); | |
321 } | |
322 | |
323 | |
324 void CacheManager::Store(int bundleIndex, | |
325 const std::string& item, | |
326 const std::string& content) | |
327 { | |
328 SanityCheck(); | |
329 | |
330 const BundleQuota quota = GetBundleQuota(bundleIndex); | |
331 | |
332 if (quota.GetMaxSpace() > 0 && | |
333 content.size() > quota.GetMaxSpace()) | |
334 { | |
335 // Cannot store such a large instance into the cache, forget about it | |
336 return; | |
337 } | |
338 | |
296
d179f3928342
removed "using namespace Orthanc"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
295
diff
changeset
|
339 std::unique_ptr<Orthanc::SQLite::Transaction> transaction(new Orthanc::SQLite::Transaction(pimpl_->db_)); |
0 | 340 transaction->Begin(); |
341 | |
342 Bundle bundle = GetBundle(bundleIndex); | |
343 | |
344 std::list<std::string> toRemove; | |
345 bundle.Add(content.size()); | |
346 MakeRoom(bundle, toRemove, bundleIndex, quota); | |
347 | |
348 // Store the cached content on the disk | |
349 const char* data = content.size() ? &content[0] : NULL; | |
296
d179f3928342
removed "using namespace Orthanc"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
295
diff
changeset
|
350 std::string uuid = Orthanc::Toolbox::GenerateUuid(); |
23
7a0af291cc90
Synchronization with Orthanc mainline
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
351 pimpl_->storage_.Create(uuid, data, content.size(), Orthanc::FileContentType_Unknown); |
0 | 352 |
353 // Remove the previous cached value. This might happen if the same | |
354 // item is accessed very quickly twice: Another factory could have | |
355 // been cached a value before the check for existence in Access(). | |
356 { | |
296
d179f3928342
removed "using namespace Orthanc"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
295
diff
changeset
|
357 Orthanc::SQLite::Statement s(pimpl_->db_, SQLITE_FROM_HERE, "SELECT seq, fileUuid, fileSize FROM Cache WHERE bundle=? AND item=?"); |
0 | 358 s.BindInt(0, bundleIndex); |
359 s.BindString(1, item); | |
360 if (s.Step()) | |
361 { | |
296
d179f3928342
removed "using namespace Orthanc"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
295
diff
changeset
|
362 Orthanc::SQLite::Statement t(pimpl_->db_, SQLITE_FROM_HERE, "DELETE FROM Cache WHERE seq=?"); |
0 | 363 t.BindInt64(0, s.ColumnInt64(0)); |
364 t.Run(); | |
365 | |
366 toRemove.push_back(s.ColumnString(1)); | |
367 bundle.Remove(s.ColumnInt64(2)); | |
368 } | |
369 } | |
370 | |
371 { | |
296
d179f3928342
removed "using namespace Orthanc"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
295
diff
changeset
|
372 Orthanc::SQLite::Statement s(pimpl_->db_, SQLITE_FROM_HERE, "INSERT INTO Cache VALUES(NULL, ?, ?, ?, ?)"); |
0 | 373 s.BindInt(0, bundleIndex); |
374 s.BindString(1, item); | |
375 s.BindString(2, uuid); | |
376 s.BindInt64(3, content.size()); | |
377 | |
378 if (!s.Run()) | |
379 { | |
197 | 380 // Error: Remove the stored file |
381 pimpl_->storage_.Remove(uuid, Orthanc::FileContentType_Unknown); | |
0 | 382 } |
197 | 383 else |
384 { | |
385 transaction->Commit(); | |
0 | 386 |
197 | 387 pimpl_->bundles_[bundleIndex] = bundle; |
0 | 388 |
197 | 389 for (std::list<std::string>::const_iterator |
390 it = toRemove.begin(); it != toRemove.end(); ++it) | |
391 { | |
392 pimpl_->storage_.Remove(*it, Orthanc::FileContentType_Unknown); | |
393 } | |
0 | 394 } |
395 } | |
396 | |
397 SanityCheck(); | |
398 } | |
399 | |
400 | |
401 | |
402 bool CacheManager::LocateInCache(std::string& uuid, | |
403 uint64_t& size, | |
404 int bundle, | |
405 const std::string& item) | |
406 { | |
407 SanityCheck(); | |
408 | |
296
d179f3928342
removed "using namespace Orthanc"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
295
diff
changeset
|
409 std::unique_ptr<Orthanc::SQLite::Transaction> transaction(new Orthanc::SQLite::Transaction(pimpl_->db_)); |
0 | 410 transaction->Begin(); |
411 | |
296
d179f3928342
removed "using namespace Orthanc"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
295
diff
changeset
|
412 Orthanc::SQLite::Statement s(pimpl_->db_, SQLITE_FROM_HERE, "SELECT seq, fileUuid, fileSize FROM Cache WHERE bundle=? AND item=?"); |
0 | 413 s.BindInt(0, bundle); |
414 s.BindString(1, item); | |
415 if (!s.Step()) | |
416 { | |
417 return false; | |
418 } | |
419 | |
420 int64_t seq = s.ColumnInt64(0); | |
421 uuid = s.ColumnString(1); | |
422 size = s.ColumnInt64(2); | |
423 | |
424 // Touch the cache to fulfill the LRU scheme. | |
296
d179f3928342
removed "using namespace Orthanc"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
295
diff
changeset
|
425 Orthanc::SQLite::Statement t(pimpl_->db_, SQLITE_FROM_HERE, "DELETE FROM Cache WHERE seq=?"); |
0 | 426 t.BindInt64(0, seq); |
427 if (t.Run()) | |
428 { | |
296
d179f3928342
removed "using namespace Orthanc"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
295
diff
changeset
|
429 Orthanc::SQLite::Statement u(pimpl_->db_, SQLITE_FROM_HERE, "INSERT INTO Cache VALUES(NULL, ?, ?, ?, ?)"); |
0 | 430 u.BindInt(0, bundle); |
431 u.BindString(1, item); | |
432 u.BindString(2, uuid); | |
433 u.BindInt64(3, size); | |
434 if (u.Run()) | |
435 { | |
436 // Everything was OK. Commit the changes to the cache. | |
437 transaction->Commit(); | |
438 return true; | |
439 } | |
440 } | |
441 | |
442 return false; | |
443 } | |
444 | |
445 | |
446 bool CacheManager::IsCached(int bundle, | |
447 const std::string& item) | |
448 { | |
449 std::string uuid; | |
450 uint64_t size; | |
451 return LocateInCache(uuid, size, bundle, item); | |
452 } | |
453 | |
454 | |
455 bool CacheManager::Access(std::string& content, | |
456 int bundle, | |
457 const std::string& item) | |
458 { | |
459 std::string uuid; | |
460 uint64_t size; | |
461 if (!LocateInCache(uuid, size, bundle, item)) | |
462 { | |
463 return false; | |
464 } | |
465 | |
466 bool ok; | |
467 try | |
468 { | |
295
fc57bf7c0c83
backward compatibility with Orthanc framework 1.8.2
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
294
diff
changeset
|
469 #if defined(ORTHANC_FRAMEWORK_VERSION_IS_ABOVE) && ORTHANC_FRAMEWORK_VERSION_IS_ABOVE(1, 9, 0) |
294
dca8013585d1
fix for new API of Orthanc::FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
293
diff
changeset
|
470 std::unique_ptr<Orthanc::IMemoryBuffer> buffer( |
dca8013585d1
fix for new API of Orthanc::FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
293
diff
changeset
|
471 pimpl_->storage_.Read(uuid, Orthanc::FileContentType_Unknown)); |
dca8013585d1
fix for new API of Orthanc::FilesystemStorage
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
293
diff
changeset
|
472 buffer->MoveToString(content); |
295
fc57bf7c0c83
backward compatibility with Orthanc framework 1.8.2
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
294
diff
changeset
|
473 #else |
fc57bf7c0c83
backward compatibility with Orthanc framework 1.8.2
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
294
diff
changeset
|
474 pimpl_->storage_.Read(content, uuid, Orthanc::FileContentType_Unknown); |
fc57bf7c0c83
backward compatibility with Orthanc framework 1.8.2
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
294
diff
changeset
|
475 #endif |
fc57bf7c0c83
backward compatibility with Orthanc framework 1.8.2
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
294
diff
changeset
|
476 |
0 | 477 ok = (content.size() == size); |
478 } | |
479 catch (std::runtime_error&) | |
480 { | |
481 ok = false; | |
482 } | |
483 | |
484 if (ok) | |
485 { | |
486 return true; | |
487 } | |
488 else | |
489 { | |
490 throw std::runtime_error("Error in the filesystem"); | |
491 } | |
492 } | |
493 | |
494 | |
495 void CacheManager::Invalidate(int bundleIndex, | |
496 const std::string& item) | |
497 { | |
498 SanityCheck(); | |
499 | |
296
d179f3928342
removed "using namespace Orthanc"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
295
diff
changeset
|
500 std::unique_ptr<Orthanc::SQLite::Transaction> transaction(new Orthanc::SQLite::Transaction(pimpl_->db_)); |
0 | 501 transaction->Begin(); |
502 | |
503 Bundle bundle = GetBundle(bundleIndex); | |
504 | |
296
d179f3928342
removed "using namespace Orthanc"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
295
diff
changeset
|
505 Orthanc::SQLite::Statement s(pimpl_->db_, SQLITE_FROM_HERE, "SELECT seq, fileUuid, fileSize FROM Cache WHERE bundle=? AND item=?"); |
0 | 506 s.BindInt(0, bundleIndex); |
507 s.BindString(1, item); | |
508 if (s.Step()) | |
509 { | |
510 int64_t seq = s.ColumnInt64(0); | |
511 const std::string uuid = s.ColumnString(1); | |
512 uint64_t expectedSize = s.ColumnInt64(2); | |
513 bundle.Remove(expectedSize); | |
514 | |
296
d179f3928342
removed "using namespace Orthanc"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
295
diff
changeset
|
515 Orthanc::SQLite::Statement t(pimpl_->db_, SQLITE_FROM_HERE, "DELETE FROM Cache WHERE seq=?"); |
0 | 516 t.BindInt64(0, seq); |
517 if (t.Run()) | |
518 { | |
519 transaction->Commit(); | |
520 pimpl_->bundles_[bundleIndex] = bundle; | |
23
7a0af291cc90
Synchronization with Orthanc mainline
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
521 pimpl_->storage_.Remove(uuid, Orthanc::FileContentType_Unknown); |
0 | 522 } |
523 } | |
524 } | |
525 | |
526 | |
527 | |
528 void CacheManager::SetBundleQuota(int bundle, | |
529 uint32_t maxCount, | |
530 uint64_t maxSpace) | |
531 { | |
532 SanityCheck(); | |
533 | |
534 const BundleQuota quota(maxCount, maxSpace); | |
535 EnsureQuota(bundle, quota); | |
536 pimpl_->quotas_[bundle] = quota; | |
537 | |
538 SanityCheck(); | |
539 } | |
540 | |
541 void CacheManager::SetDefaultQuota(uint32_t maxCount, | |
542 uint64_t maxSpace) | |
543 { | |
544 SanityCheck(); | |
545 | |
546 pimpl_->defaultQuota_ = BundleQuota(maxCount, maxSpace); | |
547 | |
296
d179f3928342
removed "using namespace Orthanc"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
295
diff
changeset
|
548 Orthanc::SQLite::Statement s(pimpl_->db_, SQLITE_FROM_HERE, "SELECT DISTINCT bundle FROM Cache"); |
0 | 549 while (s.Step()) |
550 { | |
551 EnsureQuota(s.ColumnInt(0), pimpl_->defaultQuota_); | |
552 } | |
553 | |
554 SanityCheck(); | |
555 } | |
556 | |
557 | |
558 void CacheManager::Clear() | |
559 { | |
560 SanityCheck(); | |
561 | |
296
d179f3928342
removed "using namespace Orthanc"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
295
diff
changeset
|
562 Orthanc::SQLite::Statement s(pimpl_->db_, SQLITE_FROM_HERE, "SELECT fileUuid FROM Cache"); |
0 | 563 while (s.Step()) |
564 { | |
23
7a0af291cc90
Synchronization with Orthanc mainline
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
565 pimpl_->storage_.Remove(s.ColumnString(0), Orthanc::FileContentType_Unknown); |
0 | 566 } |
567 | |
296
d179f3928342
removed "using namespace Orthanc"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
295
diff
changeset
|
568 Orthanc::SQLite::Statement t(pimpl_->db_, SQLITE_FROM_HERE, "DELETE FROM Cache"); |
0 | 569 t.Run(); |
570 | |
571 ReadBundleStatistics(); | |
572 SanityCheck(); | |
573 } | |
574 | |
575 | |
576 | |
577 void CacheManager::Clear(int bundle) | |
578 { | |
579 SanityCheck(); | |
580 | |
296
d179f3928342
removed "using namespace Orthanc"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
295
diff
changeset
|
581 Orthanc::SQLite::Statement s(pimpl_->db_, SQLITE_FROM_HERE, "SELECT fileUuid FROM Cache WHERE bundle=?"); |
0 | 582 s.BindInt(0, bundle); |
583 while (s.Step()) | |
584 { | |
23
7a0af291cc90
Synchronization with Orthanc mainline
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
585 pimpl_->storage_.Remove(s.ColumnString(0), Orthanc::FileContentType_Unknown); |
0 | 586 } |
587 | |
296
d179f3928342
removed "using namespace Orthanc"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
295
diff
changeset
|
588 Orthanc::SQLite::Statement t(pimpl_->db_, SQLITE_FROM_HERE, "DELETE FROM Cache WHERE bundle=?"); |
0 | 589 t.BindInt(0, bundle); |
590 t.Run(); | |
591 | |
592 ReadBundleStatistics(); | |
593 SanityCheck(); | |
594 } | |
115
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
595 |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
596 |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
597 void CacheManager::SetProperty(CacheProperty property, |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
598 const std::string& value) |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
599 { |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
600 Orthanc::SQLite::Statement s(pimpl_->db_, SQLITE_FROM_HERE, |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
601 "INSERT OR REPLACE INTO CacheProperties VALUES(?, ?)"); |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
602 s.BindInt(0, property); |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
603 s.BindString(1, value); |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
604 s.Run(); |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
605 } |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
606 |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
607 |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
608 bool CacheManager::LookupProperty(std::string& target, |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
609 CacheProperty property) |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
610 { |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
611 Orthanc::SQLite::Statement s(pimpl_->db_, SQLITE_FROM_HERE, |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
612 "SELECT value FROM CacheProperties WHERE property=?"); |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
613 s.BindInt(0, property); |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
614 |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
615 if (!s.Step()) |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
616 { |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
617 return false; |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
618 } |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
619 else |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
620 { |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
621 target = s.ColumnString(0); |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
622 return true; |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
623 } |
c8ca47a67bf3
automatic clearing of the cache
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
26
diff
changeset
|
624 } |
0 | 625 } |