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