Mercurial > hg > orthanc-transfers
annotate Framework/OrthancInstancesCache.cpp @ 40:1256194e1c08
sync orthanc + sdk 1.5.0 + added more info in error logs
author | Alain Mazy <am@osimis.io> |
---|---|
date | Tue, 12 Jul 2022 12:43:43 +0200 |
parents | 44a0430d7899 |
children | eb6edb022a00 |
rev | line source |
---|---|
0 | 1 /** |
2 * Transfers accelerator plugin for Orthanc | |
33
44a0430d7899
upgrade to year 2021
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
25
diff
changeset
|
3 * Copyright (C) 2018-2021 Osimis S.A., Belgium |
0 | 4 * |
5 * This program is free software: you can redistribute it and/or | |
6 * modify it under the terms of the GNU Affero General Public License | |
7 * as published by the Free Software Foundation, either version 3 of | |
8 * the License, or (at your option) any later version. | |
9 * | |
10 * This program is distributed in the hope that it will be useful, but | |
11 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 * Affero General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Affero General Public License | |
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
17 **/ | |
18 | |
19 | |
20 #include "OrthancInstancesCache.h" | |
21 | |
25
dfc43678aecb
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
19
diff
changeset
|
22 #include <Compatibility.h> // For std::unique_ptr |
0 | 23 |
24 namespace OrthancPlugins | |
25 { | |
26 void OrthancInstancesCache::CacheAccessor::CheckValid() const | |
27 { | |
28 if (instance_ == NULL) | |
29 { | |
30 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
31 } | |
32 } | |
33 | |
34 | |
35 OrthancInstancesCache::CacheAccessor::CacheAccessor(OrthancInstancesCache& cache, | |
36 const std::string& instanceId) : | |
37 lock_(cache.mutex_), | |
38 instance_(NULL) | |
39 { | |
40 cache.CheckInvariants(); | |
41 | |
42 if (cache.index_.Contains(instanceId)) | |
43 { | |
44 // Move the instance at the end of the LRU recycling | |
45 cache.index_.MakeMostRecent(instanceId); | |
46 | |
47 Content::const_iterator instance = cache.content_.find(instanceId); | |
48 assert(instance != cache.content_.end() && | |
49 instance->first == instanceId && | |
50 instance->second != NULL); | |
51 | |
52 instance_ = instance->second; | |
53 } | |
54 } | |
55 | |
56 | |
57 const DicomInstanceInfo& OrthancInstancesCache::CacheAccessor::GetInfo() const | |
58 { | |
59 CheckValid(); | |
60 return instance_->GetInfo(); | |
61 } | |
62 | |
63 | |
64 void OrthancInstancesCache::CacheAccessor::GetChunk(std::string& chunk, | |
65 std::string& md5, | |
66 size_t offset, | |
67 size_t size) | |
68 { | |
69 CheckValid(); | |
70 return instance_->GetChunk(chunk, md5, offset, size); | |
71 } | |
72 | |
73 | |
74 void OrthancInstancesCache::CheckInvariants() | |
75 { | |
76 #ifndef NDEBUG | |
77 size_t s = 0; | |
78 | |
79 assert(content_.size() == index_.GetSize()); | |
80 | |
81 for (Content::const_iterator it = content_.begin(); | |
82 it != content_.end(); ++it) | |
83 { | |
84 assert(it->second != NULL); | |
85 s += it->second->GetInfo().GetSize(); | |
86 | |
87 assert(index_.Contains(it->first)); | |
88 } | |
89 | |
90 assert(s == memorySize_); | |
91 | |
92 if (memorySize_ > maxMemorySize_) | |
93 { | |
94 // It is only allowed to overtake the max memory size if the | |
95 // cache contains a single, large DICOM instance | |
96 assert(index_.GetSize() == 1 && | |
97 content_.size() == 1 && | |
98 memorySize_ == (content_.begin())->second->GetInfo().GetSize()); | |
99 } | |
100 #endif | |
101 } | |
102 | |
103 | |
104 void OrthancInstancesCache::RemoveOldest() | |
105 { | |
106 CheckInvariants(); | |
107 | |
108 assert(!index_.IsEmpty()); | |
109 | |
110 std::string oldest = index_.RemoveOldest(); | |
111 | |
112 Content::iterator instance = content_.find(oldest); | |
113 assert(instance != content_.end() && | |
114 instance->second != NULL); | |
115 | |
116 memorySize_ -= instance->second->GetInfo().GetSize(); | |
117 delete instance->second; | |
118 content_.erase(instance); | |
119 } | |
120 | |
121 | |
122 void OrthancInstancesCache::Store(const std::string& instanceId, | |
25
dfc43678aecb
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
19
diff
changeset
|
123 std::unique_ptr<SourceDicomInstance>& instance) |
0 | 124 { |
125 if (instance.get() == NULL) | |
126 { | |
127 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | |
128 } | |
129 | |
130 if (index_.Contains(instanceId)) | |
131 { | |
132 // This instance has been read by another thread since the cache | |
133 // lookup, give up | |
134 index_.MakeMostRecent(instanceId); | |
135 return; | |
136 } | |
137 else | |
138 { | |
139 // Make room in the cache for the new instance | |
140 while (!index_.IsEmpty() && | |
141 memorySize_ + instance->GetInfo().GetSize() > maxMemorySize_) | |
142 { | |
143 RemoveOldest(); | |
144 } | |
145 | |
146 CheckInvariants(); | |
147 | |
148 index_.AddOrMakeMostRecent(instanceId); | |
149 memorySize_ += instance->GetInfo().GetSize(); | |
150 content_[instanceId] = instance.release(); | |
151 | |
152 CheckInvariants(); | |
153 } | |
154 } | |
155 | |
156 | |
8
4c3437217518
fix for compatibility with simplified OrthancPluginCppWrapper
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
157 OrthancInstancesCache::OrthancInstancesCache() : |
0 | 158 memorySize_(0), |
159 maxMemorySize_(512 * MB) // 512 MB by default | |
160 { | |
161 } | |
162 | |
163 | |
164 OrthancInstancesCache::~OrthancInstancesCache() | |
165 { | |
166 CheckInvariants(); | |
167 | |
168 for (Content::iterator it = content_.begin(); | |
169 it != content_.end(); ++it) | |
170 { | |
171 assert(it->second != NULL); | |
172 delete it->second; | |
173 } | |
174 } | |
175 | |
176 | |
177 size_t OrthancInstancesCache::GetMemorySize() | |
178 { | |
179 boost::mutex::scoped_lock lock(mutex_); | |
180 return memorySize_; | |
181 } | |
182 | |
183 | |
184 size_t OrthancInstancesCache::GetMaxMemorySize() | |
185 { | |
186 boost::mutex::scoped_lock lock(mutex_); | |
187 return maxMemorySize_; | |
188 } | |
189 | |
190 | |
191 void OrthancInstancesCache::SetMaxMemorySize(size_t size) | |
192 { | |
193 if (size <= 0) | |
194 { | |
195 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
196 } | |
197 | |
198 boost::mutex::scoped_lock lock(mutex_); | |
199 | |
200 while (memorySize_ > size) | |
201 { | |
202 RemoveOldest(); | |
203 } | |
204 | |
205 maxMemorySize_ = size; | |
206 CheckInvariants(); | |
207 } | |
208 | |
209 | |
210 void OrthancInstancesCache::GetInstanceInfo(size_t& size, | |
211 std::string& md5, | |
212 const std::string& instanceId) | |
213 { | |
214 // Check whether the instance is part of the cache | |
215 { | |
216 CacheAccessor accessor(*this, instanceId); | |
217 if (accessor.IsValid()) | |
218 { | |
219 size = accessor.GetInfo().GetSize(); | |
220 md5 = accessor.GetInfo().GetMD5(); | |
221 return; | |
222 } | |
223 } | |
224 | |
225 // The instance was not in the cache, load it | |
25
dfc43678aecb
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
19
diff
changeset
|
226 std::unique_ptr<SourceDicomInstance> instance(new SourceDicomInstance(instanceId)); |
0 | 227 size = instance->GetInfo().GetSize(); |
228 md5 = instance->GetInfo().GetMD5(); | |
229 | |
230 // Store the just-loaded DICOM instance into the cache | |
231 { | |
232 boost::mutex::scoped_lock lock(mutex_); | |
233 Store(instanceId, instance); | |
234 } | |
235 } | |
236 | |
237 | |
238 void OrthancInstancesCache::GetChunk(std::string& chunk, | |
239 std::string& md5, | |
240 const std::string& instanceId, | |
241 size_t offset, | |
242 size_t size) | |
243 { | |
244 // Check whether the instance is part of the cache | |
245 { | |
246 CacheAccessor accessor(*this, instanceId); | |
247 if (accessor.IsValid()) | |
248 { | |
249 accessor.GetChunk(chunk, md5, offset, size); | |
250 return; | |
251 } | |
252 } | |
253 | |
254 // The instance was not in the cache, load it | |
25
dfc43678aecb
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
19
diff
changeset
|
255 std::unique_ptr<SourceDicomInstance> instance(new SourceDicomInstance(instanceId)); |
0 | 256 instance->GetChunk(chunk, md5, 0, instance->GetInfo().GetSize()); |
257 | |
258 // Store the just-loaded DICOM instance into the cache | |
259 { | |
260 boost::mutex::scoped_lock lock(mutex_); | |
261 Store(instanceId, instance); | |
262 } | |
263 } | |
264 | |
265 | |
266 void OrthancInstancesCache::GetChunk(std::string& chunk, | |
267 std::string& md5, | |
268 const TransferBucket& bucket, | |
269 size_t chunkIndex) | |
270 { | |
271 GetChunk(chunk, md5, bucket.GetChunkInstanceId(chunkIndex), | |
272 bucket.GetChunkOffset(chunkIndex), | |
273 bucket.GetChunkSize(chunkIndex)); | |
274 } | |
275 } |