comparison Framework/Deprecated/Loaders/LoaderCache.cpp @ 1225:16738485e457 broker

deprecating DicomStructureSetLoader, OrthancMultiframeVolumeLoader and OrthancSeriesVolumeProgressiveLoader
author Sebastien Jodogne <s.jodogne@gmail.com>
date Sun, 08 Dec 2019 11:45:09 +0100
parents Framework/Loaders/LoaderCache.cpp@477203923f26
children 05d05cba0f4f
comparison
equal deleted inserted replaced
1224:37bc7f115f81 1225:16738485e457
1 /**
2 * Stone of Orthanc
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2019 Osimis S.A., Belgium
6 *
7 * This program is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU 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 #include "LoaderCache.h"
22
23 #include "../../StoneException.h"
24 #include "OrthancSeriesVolumeProgressiveLoader.h"
25 #include "OrthancMultiframeVolumeLoader.h"
26 #include "DicomStructureSetLoader.h"
27
28 #ifdef BGO_ENABLE_DICOMSTRUCTURESETLOADER2
29 #include "DicomStructureSetLoader2.h"
30 #endif
31 //BGO_ENABLE_DICOMSTRUCTURESETLOADER2
32
33
34 #if ORTHANC_ENABLE_WASM == 1
35 # include <unistd.h>
36 # include "../../Oracle/WebAssemblyOracle.h"
37 #else
38 # include "../../Oracle/ThreadedOracle.h"
39 #endif
40
41 #ifdef BGO_ENABLE_DICOMSTRUCTURESETLOADER2
42 #include "../../Toolbox/DicomStructureSet2.h"
43 #endif
44 //BGO_ENABLE_DICOMSTRUCTURESETLOADER2
45
46 #include "../../Volumes/DicomVolumeImage.h"
47 #include "../../Volumes/DicomVolumeImageMPRSlicer.h"
48
49 #ifdef BGO_ENABLE_DICOMSTRUCTURESETLOADER2
50 #include "../../Volumes/DicomStructureSetSlicer2.h"
51 #endif
52 //BGO_ENABLE_DICOMSTRUCTURESETLOADER2
53
54 #include <Core/OrthancException.h>
55 #include <Core/Toolbox.h>
56
57 namespace Deprecated
58 {
59 #if ORTHANC_ENABLE_WASM == 1
60 LoaderCache::LoaderCache(OrthancStone::WebAssemblyOracle& oracle)
61 : oracle_(oracle)
62 {
63
64 }
65 #else
66 LoaderCache::LoaderCache(OrthancStone::ThreadedOracle& oracle,
67 OrthancStone::Deprecated::LockingEmitter& lockingEmitter)
68 : oracle_(oracle)
69 , lockingEmitter_(lockingEmitter)
70 {
71 }
72 #endif
73
74 boost::shared_ptr<OrthancSeriesVolumeProgressiveLoader>
75 LoaderCache::GetSeriesVolumeProgressiveLoader(std::string seriesUuid)
76 {
77 try
78 {
79
80 // normalize keys a little
81 seriesUuid = Orthanc::Toolbox::StripSpaces(seriesUuid);
82 Orthanc::Toolbox::ToLowerCase(seriesUuid);
83
84 // find in cache
85 if (seriesVolumeProgressiveLoaders_.find(seriesUuid) == seriesVolumeProgressiveLoaders_.end())
86 {
87 // LOG(TRACE) << "LoaderCache::GetSeriesVolumeProgressiveLoader : CACHEMISS --> need to load seriesUUid = " << seriesUuid;
88 #if ORTHANC_ENABLE_WASM == 1
89 // LOG(TRACE) << "Performing request for series " << seriesUuid << " sbrk(0) = " << sbrk(0);
90 #else
91 // LOG(TRACE) << "Performing request for series " << seriesUuid;
92 #endif
93 boost::shared_ptr<OrthancStone::DicomVolumeImage> volumeImage(new OrthancStone::DicomVolumeImage);
94 boost::shared_ptr<OrthancSeriesVolumeProgressiveLoader> loader;
95 // LOG(TRACE) << "volumeImage = " << volumeImage.get();
96 {
97 #if ORTHANC_ENABLE_WASM == 1
98 loader.reset(new OrthancSeriesVolumeProgressiveLoader(volumeImage, oracle_, oracle_));
99 #else
100 OrthancStone::Deprecated::LockingEmitter::WriterLock lock(lockingEmitter_);
101 loader.reset(new OrthancSeriesVolumeProgressiveLoader(volumeImage, oracle_, lock.GetOracleObservable()));
102 #endif
103 // LOG(TRACE) << "LoaderCache::GetSeriesVolumeProgressiveLoader : loader = " << loader.get();
104 loader->LoadSeries(seriesUuid);
105 // LOG(TRACE) << "LoaderCache::GetSeriesVolumeProgressiveLoader : loader->LoadSeries successful";
106 }
107 seriesVolumeProgressiveLoaders_[seriesUuid] = loader;
108 }
109 else
110 {
111 // LOG(TRACE) << "LoaderCache::GetSeriesVolumeProgressiveLoader : returning cached loader for seriesUUid = " << seriesUuid;
112 }
113 return seriesVolumeProgressiveLoaders_[seriesUuid];
114 }
115 catch (const Orthanc::OrthancException& e)
116 {
117 if (e.HasDetails())
118 {
119 LOG(ERROR) << "OrthancException in LoaderCache: " << e.What() << " Details: " << e.GetDetails();
120 }
121 else
122 {
123 LOG(ERROR) << "OrthancException in LoaderCache: " << e.What();
124 }
125 throw;
126 }
127 catch (const std::exception& e)
128 {
129 LOG(ERROR) << "std::exception in LoaderCache: " << e.what();
130 throw;
131 }
132 catch (...)
133 {
134 LOG(ERROR) << "Unknown exception in LoaderCache";
135 throw;
136 }
137 }
138
139 boost::shared_ptr<OrthancMultiframeVolumeLoader> LoaderCache::GetMultiframeVolumeLoader(std::string instanceUuid)
140 {
141 // if the loader is not available, let's trigger its creation
142 if(multiframeVolumeLoaders_.find(instanceUuid) == multiframeVolumeLoaders_.end())
143 {
144 GetMultiframeDicomVolumeImageMPRSlicer(instanceUuid);
145 }
146 ORTHANC_ASSERT(multiframeVolumeLoaders_.find(instanceUuid) != multiframeVolumeLoaders_.end());
147
148 return multiframeVolumeLoaders_[instanceUuid];
149 }
150
151 boost::shared_ptr<OrthancStone::DicomVolumeImageMPRSlicer> LoaderCache::GetMultiframeDicomVolumeImageMPRSlicer(std::string instanceUuid)
152 {
153 try
154 {
155 // normalize keys a little
156 instanceUuid = Orthanc::Toolbox::StripSpaces(instanceUuid);
157 Orthanc::Toolbox::ToLowerCase(instanceUuid);
158
159 // find in cache
160 if (dicomVolumeImageMPRSlicers_.find(instanceUuid) == dicomVolumeImageMPRSlicers_.end())
161 {
162 boost::shared_ptr<OrthancStone::DicomVolumeImage> volumeImage(new OrthancStone::DicomVolumeImage);
163 boost::shared_ptr<OrthancMultiframeVolumeLoader> loader;
164
165 {
166 #if ORTHANC_ENABLE_WASM == 1
167 loader.reset(new OrthancMultiframeVolumeLoader(volumeImage, oracle_, oracle_));
168 #else
169 OrthancStone::Deprecated::LockingEmitter::WriterLock lock(lockingEmitter_);
170 loader.reset(new OrthancMultiframeVolumeLoader(volumeImage, oracle_, lock.GetOracleObservable()));
171 #endif
172 loader->LoadInstance(instanceUuid);
173 }
174 multiframeVolumeLoaders_[instanceUuid] = loader;
175 boost::shared_ptr<OrthancStone::DicomVolumeImageMPRSlicer> mprSlicer(new OrthancStone::DicomVolumeImageMPRSlicer(volumeImage));
176 dicomVolumeImageMPRSlicers_[instanceUuid] = mprSlicer;
177 }
178 return dicomVolumeImageMPRSlicers_[instanceUuid];
179 }
180 catch (const Orthanc::OrthancException& e)
181 {
182 if (e.HasDetails())
183 {
184 LOG(ERROR) << "OrthancException in LoaderCache: " << e.What() << " Details: " << e.GetDetails();
185 }
186 else
187 {
188 LOG(ERROR) << "OrthancException in LoaderCache: " << e.What();
189 }
190 throw;
191 }
192 catch (const std::exception& e)
193 {
194 LOG(ERROR) << "std::exception in LoaderCache: " << e.what();
195 throw;
196 }
197 catch (...)
198 {
199 LOG(ERROR) << "Unknown exception in LoaderCache";
200 throw;
201 }
202 }
203
204 #ifdef BGO_ENABLE_DICOMSTRUCTURESETLOADER2
205
206 boost::shared_ptr<DicomStructureSetSlicer2> LoaderCache::GetDicomStructureSetSlicer2(std::string instanceUuid)
207 {
208 // if the loader is not available, let's trigger its creation
209 if (dicomStructureSetSlicers2_.find(instanceUuid) == dicomStructureSetSlicers2_.end())
210 {
211 GetDicomStructureSetLoader2(instanceUuid);
212 }
213 ORTHANC_ASSERT(dicomStructureSetSlicers2_.find(instanceUuid) != dicomStructureSetSlicers2_.end());
214
215 return dicomStructureSetSlicers2_[instanceUuid];
216 }
217 #endif
218 //BGO_ENABLE_DICOMSTRUCTURESETLOADER2
219
220
221 /**
222 This method allows to convert a list of string into a string by
223 sorting the strings then joining them
224 */
225 static std::string SortAndJoin(const std::vector<std::string>& stringList)
226 {
227 if (stringList.size() == 0)
228 {
229 return "";
230 }
231 else
232 {
233 std::vector<std::string> sortedStringList = stringList;
234 std::sort(sortedStringList.begin(), sortedStringList.end());
235 std::stringstream s;
236 s << sortedStringList[0];
237 for (size_t i = 1; i < sortedStringList.size(); ++i)
238 {
239 s << "-" << sortedStringList[i];
240 }
241 return s.str();
242 }
243 }
244
245 boost::shared_ptr<DicomStructureSetLoader>
246 LoaderCache::GetDicomStructureSetLoader(
247 std::string inInstanceUuid,
248 const std::vector<std::string>& initiallyVisibleStructures)
249 {
250 try
251 {
252 // normalize keys a little
253 inInstanceUuid = Orthanc::Toolbox::StripSpaces(inInstanceUuid);
254 Orthanc::Toolbox::ToLowerCase(inInstanceUuid);
255
256 std::string initiallyVisibleStructuresKey =
257 SortAndJoin(initiallyVisibleStructures);
258
259 std::string entryKey = inInstanceUuid + "_" + initiallyVisibleStructuresKey;
260
261 // find in cache
262 if (dicomStructureSetLoaders_.find(entryKey) == dicomStructureSetLoaders_.end())
263 {
264 boost::shared_ptr<DicomStructureSetLoader> loader;
265
266 {
267 #if ORTHANC_ENABLE_WASM == 1
268 loader.reset(new DicomStructureSetLoader(oracle_, oracle_));
269 #else
270 OrthancStone::Deprecated::LockingEmitter::WriterLock lock(lockingEmitter_);
271 loader.reset(new DicomStructureSetLoader(oracle_, lock.GetOracleObservable()));
272 #endif
273 loader->LoadInstance(inInstanceUuid, initiallyVisibleStructures);
274 }
275 dicomStructureSetLoaders_[entryKey] = loader;
276 }
277 return dicomStructureSetLoaders_[entryKey];
278 }
279 catch (const Orthanc::OrthancException& e)
280 {
281 if (e.HasDetails())
282 {
283 LOG(ERROR) << "OrthancException in LoaderCache: " << e.What() << " Details: " << e.GetDetails();
284 }
285 else
286 {
287 LOG(ERROR) << "OrthancException in LoaderCache: " << e.What();
288 }
289 throw;
290 }
291 catch (const std::exception& e)
292 {
293 LOG(ERROR) << "std::exception in LoaderCache: " << e.what();
294 throw;
295 }
296 catch (...)
297 {
298 LOG(ERROR) << "Unknown exception in LoaderCache";
299 throw;
300 }
301 }
302
303 #ifdef BGO_ENABLE_DICOMSTRUCTURESETLOADER2
304
305 boost::shared_ptr<DicomStructureSetLoader2> LoaderCache::GetDicomStructureSetLoader2(std::string instanceUuid)
306 {
307 try
308 {
309 // normalize keys a little
310 instanceUuid = Orthanc::Toolbox::StripSpaces(instanceUuid);
311 Orthanc::Toolbox::ToLowerCase(instanceUuid);
312
313 // find in cache
314 if (dicomStructureSetLoaders2_.find(instanceUuid) == dicomStructureSetLoaders2_.end())
315 {
316 boost::shared_ptr<DicomStructureSetLoader2> loader;
317 boost::shared_ptr<DicomStructureSet2> structureSet(new DicomStructureSet2());
318 boost::shared_ptr<DicomStructureSetSlicer2> rtSlicer(new DicomStructureSetSlicer2(structureSet));
319 dicomStructureSetSlicers2_[instanceUuid] = rtSlicer;
320 dicomStructureSets2_[instanceUuid] = structureSet; // to prevent it from being deleted
321 {
322 #if ORTHANC_ENABLE_WASM == 1
323 loader.reset(new DicomStructureSetLoader2(*(structureSet.get()), oracle_, oracle_));
324 #else
325 LockingEmitter::WriterLock lock(lockingEmitter_);
326 // TODO: clarify lifetimes... this is DANGEROUS!
327 loader.reset(new DicomStructureSetLoader2(*(structureSet.get()), oracle_, lock.GetOracleObservable()));
328 #endif
329 loader->LoadInstance(instanceUuid);
330 }
331 dicomStructureSetLoaders2_[instanceUuid] = loader;
332 }
333 return dicomStructureSetLoaders2_[instanceUuid];
334 }
335 catch (const Orthanc::OrthancException& e)
336 {
337 if (e.HasDetails())
338 {
339 LOG(ERROR) << "OrthancException in GetDicomStructureSetLoader2: " << e.What() << " Details: " << e.GetDetails();
340 }
341 else
342 {
343 LOG(ERROR) << "OrthancException in GetDicomStructureSetLoader2: " << e.What();
344 }
345 throw;
346 }
347 catch (const std::exception& e)
348 {
349 LOG(ERROR) << "std::exception in GetDicomStructureSetLoader2: " << e.what();
350 throw;
351 }
352 catch (...)
353 {
354 LOG(ERROR) << "Unknown exception in GetDicomStructureSetLoader2";
355 throw;
356 }
357 }
358
359 #endif
360 // BGO_ENABLE_DICOMSTRUCTURESETLOADER2
361
362
363 void LoaderCache::ClearCache()
364 {
365 #if ORTHANC_ENABLE_WASM != 1
366 OrthancStone::Deprecated::LockingEmitter::WriterLock lock(lockingEmitter_);
367 #endif
368
369 //#ifndef NDEBUG
370 // ISO way of checking for debug builds
371 DebugDisplayObjRefCounts();
372 //#endif
373 seriesVolumeProgressiveLoaders_.clear();
374 multiframeVolumeLoaders_.clear();
375 dicomVolumeImageMPRSlicers_.clear();
376 dicomStructureSetLoaders_.clear();
377
378 #ifdef BGO_ENABLE_DICOMSTRUCTURESETLOADER2
379 // order is important!
380 dicomStructureSetLoaders2_.clear();
381 dicomStructureSetSlicers2_.clear();
382 dicomStructureSets2_.clear();
383 #endif
384 // BGO_ENABLE_DICOMSTRUCTURESETLOADER2
385 }
386
387 template<typename T> void DebugDisplayObjRefCountsInMap(
388 const std::string& name, const std::map<std::string, boost::shared_ptr<T> >& myMap)
389 {
390 LOG(TRACE) << "Map \"" << name << "\" ref counts:";
391 size_t i = 0;
392 for (typename std::map<std::string, boost::shared_ptr<T> >::const_iterator
393 it = myMap.begin(); it != myMap.end(); ++it)
394 {
395 LOG(TRACE) << " element #" << i << ": ref count = " << it->second.use_count();
396 i++;
397 }
398 }
399
400 void LoaderCache::DebugDisplayObjRefCounts()
401 {
402 DebugDisplayObjRefCountsInMap("seriesVolumeProgressiveLoaders_", seriesVolumeProgressiveLoaders_);
403 DebugDisplayObjRefCountsInMap("multiframeVolumeLoaders_", multiframeVolumeLoaders_);
404 DebugDisplayObjRefCountsInMap("dicomVolumeImageMPRSlicers_", dicomVolumeImageMPRSlicers_);
405 DebugDisplayObjRefCountsInMap("dicomStructureSetLoaders_", dicomStructureSetLoaders_);
406 #ifdef BGO_ENABLE_DICOMSTRUCTURESETLOADER2
407 DebugDisplayObjRefCountsInMap("dicomStructureSetLoaders2_", dicomStructureSetLoaders2_);
408 DebugDisplayObjRefCountsInMap("dicomStructureSetSlicers2_", dicomStructureSetSlicers2_);
409 #endif
410 //BGO_ENABLE_DICOMSTRUCTURESETLOADER2
411 }
412 }