Mercurial > hg > orthanc-stone
comparison Framework/Oracle/GenericOracleRunner.cpp @ 1136:42581a6182c8 broker
reactivation of the cache of parsed DICOM files
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 06 Nov 2019 17:54:14 +0100 |
parents | a0a33e5ea5bb |
children | cc029987b6dc |
comparison
equal
deleted
inserted
replaced
1135:a0a33e5ea5bb | 1136:42581a6182c8 |
---|---|
236 emitter.EmitMessage(receiver, message); | 236 emitter.EmitMessage(receiver, message); |
237 } | 237 } |
238 | 238 |
239 | 239 |
240 #if ORTHANC_ENABLE_DCMTK == 1 | 240 #if ORTHANC_ENABLE_DCMTK == 1 |
241 static void RunInternal(boost::weak_ptr<IObserver> receiver, | 241 namespace |
242 IMessageEmitter& emitter, | 242 { |
243 const std::string& root, | 243 class IDicomHandler : public boost::noncopyable |
244 const ParseDicomFileCommand& command) | 244 { |
245 { | 245 public: |
246 std::string path = GetPath(root, command.GetPath()); | 246 virtual ~IDicomHandler() |
247 | 247 { |
248 if (!Orthanc::SystemToolbox::IsRegularFile(path)) | 248 } |
249 { | 249 |
250 throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentFile); | 250 virtual void Handle(Orthanc::ParsedDicomFile* dicom, |
251 } | 251 const ParseDicomFileCommand& command, |
252 | 252 uint64_t fileSize) = 0; |
253 uint64_t fileSize = Orthanc::SystemToolbox::GetFileSize(path); | 253 |
254 | 254 static void Apply(IDicomHandler& handler, |
255 // Check for 32bit systems | 255 const std::string& root, |
256 if (fileSize != static_cast<uint64_t>(static_cast<size_t>(fileSize))) | 256 const ParseDicomFileCommand& command) |
257 { | 257 { |
258 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotEnoughMemory); | 258 std::string path = GetPath(root, command.GetPath()); |
259 } | 259 |
260 | 260 if (!Orthanc::SystemToolbox::IsRegularFile(path)) |
261 DcmFileFormat dicom; | 261 { |
262 bool ok; | 262 throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentFile); |
263 | 263 } |
264 if (command.IsPixelDataIncluded()) | 264 |
265 { | 265 uint64_t fileSize = Orthanc::SystemToolbox::GetFileSize(path); |
266 ok = dicom.loadFile(path.c_str()).good(); | 266 |
267 } | 267 // Check for 32bit systems |
268 else | 268 if (fileSize != static_cast<uint64_t>(static_cast<size_t>(fileSize))) |
269 { | 269 { |
270 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotEnoughMemory); | |
271 } | |
272 | |
273 DcmFileFormat dicom; | |
274 bool ok; | |
275 | |
276 if (command.IsPixelDataIncluded()) | |
277 { | |
278 ok = dicom.loadFile(path.c_str()).good(); | |
279 } | |
280 else | |
281 { | |
270 #if DCMTK_VERSION_NUMBER >= 362 | 282 #if DCMTK_VERSION_NUMBER >= 362 |
271 // NB : We could stop at (0x3007, 0x0000) instead of | 283 // NB : We could stop at (0x3007, 0x0000) instead of |
272 // DCM_PixelData, cf. the Orthanc::DICOM_TAG_* constants | 284 // DCM_PixelData, cf. the Orthanc::DICOM_TAG_* constants |
273 | 285 |
274 static const DcmTagKey STOP = DCM_PixelData; | 286 static const DcmTagKey STOP = DCM_PixelData; |
275 //static const DcmTagKey STOP(0x3007, 0x0000); | 287 //static const DcmTagKey STOP(0x3007, 0x0000); |
276 | 288 |
277 ok = dicom.loadFileUntilTag(path.c_str(), EXS_Unknown, EGL_noChange, | 289 ok = dicom.loadFileUntilTag(path.c_str(), EXS_Unknown, EGL_noChange, |
278 DCM_MaxReadLength, ERM_autoDetect, STOP).good(); | 290 DCM_MaxReadLength, ERM_autoDetect, STOP).good(); |
279 #else | 291 #else |
280 // The primitive "loadFileUntilTag" was introduced in DCMTK 3.6.2 | 292 // The primitive "loadFileUntilTag" was introduced in DCMTK 3.6.2 |
281 ok = dicom.loadFile(path.c_str()).good(); | 293 ok = dicom.loadFile(path.c_str()).good(); |
282 #endif | 294 #endif |
283 } | 295 } |
284 | 296 |
285 printf("Reading %s\n", path.c_str()); | 297 printf("Reading %s\n", path.c_str()); |
286 | 298 |
287 if (ok) | 299 if (ok) |
288 { | 300 { |
289 Orthanc::ParsedDicomFile parsed(dicom); | 301 handler.Handle(new Orthanc::ParsedDicomFile(dicom), command, fileSize); |
290 ParseDicomFileCommand::SuccessMessage message | 302 } |
291 (command, parsed, static_cast<size_t>(fileSize), command.IsPixelDataIncluded()); | 303 else |
292 emitter.EmitMessage(receiver, message); | 304 { |
293 } | 305 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, |
294 else | 306 "Cannot parse file: " + path); |
295 { | 307 } |
296 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, | 308 } |
297 "Cannot parse file: " + path); | 309 }; |
298 } | 310 |
311 | |
312 class DicomHandlerWithoutCache : public IDicomHandler | |
313 { | |
314 private: | |
315 boost::weak_ptr<IObserver> receiver_; | |
316 IMessageEmitter& emitter_; | |
317 | |
318 public: | |
319 DicomHandlerWithoutCache(boost::weak_ptr<IObserver> receiver, | |
320 IMessageEmitter& emitter) : | |
321 receiver_(receiver), | |
322 emitter_(emitter) | |
323 { | |
324 } | |
325 | |
326 virtual void Handle(Orthanc::ParsedDicomFile* dicom, | |
327 const ParseDicomFileCommand& command, | |
328 uint64_t fileSize) | |
329 { | |
330 std::auto_ptr<Orthanc::ParsedDicomFile> parsed(dicom); | |
331 | |
332 ParseDicomFileCommand::SuccessMessage message | |
333 (command, *parsed, static_cast<size_t>(fileSize), command.IsPixelDataIncluded()); | |
334 emitter_.EmitMessage(receiver_, message); | |
335 } | |
336 }; | |
337 | |
338 | |
339 class DicomHandlerWithCache : public IDicomHandler | |
340 { | |
341 private: | |
342 boost::weak_ptr<IObserver> receiver_; | |
343 IMessageEmitter& emitter_; | |
344 boost::shared_ptr<ParsedDicomFileCache> cache_; | |
345 | |
346 public: | |
347 DicomHandlerWithCache(boost::weak_ptr<IObserver> receiver, | |
348 IMessageEmitter& emitter, | |
349 boost::shared_ptr<ParsedDicomFileCache> cache) : | |
350 receiver_(receiver), | |
351 emitter_(emitter), | |
352 cache_(cache) | |
353 { | |
354 if (!cache) | |
355 { | |
356 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | |
357 } | |
358 } | |
359 | |
360 virtual void Handle(Orthanc::ParsedDicomFile* dicom, | |
361 const ParseDicomFileCommand& command, | |
362 uint64_t fileSize) | |
363 { | |
364 std::auto_ptr<Orthanc::ParsedDicomFile> parsed(dicom); | |
365 | |
366 { | |
367 ParseDicomFileCommand::SuccessMessage message | |
368 (command, *parsed, static_cast<size_t>(fileSize), command.IsPixelDataIncluded()); | |
369 emitter_.EmitMessage(receiver_, message); | |
370 } | |
371 | |
372 // Store it into the cache for future use | |
373 assert(cache_); | |
374 cache_->Acquire(command.GetPath(), parsed.release(), | |
375 static_cast<size_t>(fileSize), command.IsPixelDataIncluded()); | |
376 } | |
377 }; | |
299 } | 378 } |
300 | 379 |
301 | 380 |
302 static void RunInternal(boost::weak_ptr<IObserver> receiver, | 381 static void RunInternal(boost::weak_ptr<IObserver> receiver, |
303 IMessageEmitter& emitter, | 382 IMessageEmitter& emitter, |
304 boost::shared_ptr<ParsedDicomFileCache> cache, | 383 boost::shared_ptr<ParsedDicomFileCache> cache, |
305 const std::string& root, | 384 const std::string& root, |
306 const ParseDicomFileCommand& command) | 385 const ParseDicomFileCommand& command) |
307 { | 386 { |
308 #if 0 | 387 #if 1 |
309 // The code to use the cache is buggy in multithreaded environments => TODO FIX | |
310 if (cache.get()) | 388 if (cache.get()) |
311 { | 389 { |
312 { | 390 { |
313 ParsedDicomFileCache::Reader reader(*cache, command.GetPath()); | 391 ParsedDicomFileCache::Reader reader(*cache, command.GetPath()); |
314 if (reader.IsValid() && | 392 if (reader.IsValid() && |
315 (!command.IsPixelDataIncluded() || | 393 (!command.IsPixelDataIncluded() || |
316 reader.HasPixelData())) | 394 reader.HasPixelData())) |
317 { | 395 { |
318 // Reuse the DICOM file from the cache | 396 // Reuse the DICOM file from the cache |
319 return new ParseDicomFileCommand::SuccessMessage( | 397 ParseDicomFileCommand::SuccessMessage message( |
320 command, reader.GetDicom(), reader.GetFileSize(), reader.HasPixelData()); | 398 command, reader.GetDicom(), reader.GetFileSize(), reader.HasPixelData()); |
321 emitter.EmitMessage(receiver, message); | 399 emitter.EmitMessage(receiver, message); |
322 return; | 400 return; |
323 } | 401 } |
324 } | 402 } |
325 | 403 |
326 // Not in the cache, first read and parse the DICOM file | 404 DicomHandlerWithCache handler(receiver, emitter, cache); |
327 std::auto_ptr<ParseDicomFileCommand::SuccessMessage> message(RunInternal(root, command)); | 405 IDicomHandler::Apply(handler, root, command); |
328 | |
329 // Secondly, store it into the cache for future use | |
330 assert(&message->GetOrigin() == &command); | |
331 cache->Acquire(message->GetOrigin().GetPath(), message->GetDicom(), | |
332 message->GetFileSize(), message->HasPixelData()); | |
333 | |
334 return message.release(); | |
335 } | 406 } |
336 else | 407 else |
337 { | 408 { |
338 // No cache available | 409 // No cache available |
339 return RunInternal(root, command); | 410 DicomHandlerWithoutCache handler(receiver, emitter); |
411 IDicomHandler::Apply(handler, root, command); | |
340 } | 412 } |
341 #else | 413 #else |
342 return RunInternal(receiver, emitter, root, command); | 414 DicomHandlerWithoutCache handler(receiver, emitter); |
415 IDicomHandler::Apply(handler, root, command); | |
343 #endif | 416 #endif |
344 } | 417 } |
345 | 418 |
346 #endif | 419 #endif |
347 | 420 |