Mercurial > hg > orthanc
comparison OrthancServer/ServerIndex.cpp @ 1247:32fcc5dc7562
abstraction
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 08 Dec 2014 13:54:27 +0100 |
parents | 54bf0f0245f4 |
children | 40725595aaf0 |
comparison
equal
deleted
inserted
replaced
1246:54bf0f0245f4 | 1247:32fcc5dc7562 |
---|---|
219 public: | 219 public: |
220 Transaction(ServerIndex& index) : | 220 Transaction(ServerIndex& index) : |
221 index_(index), | 221 index_(index), |
222 isCommitted_(false) | 222 isCommitted_(false) |
223 { | 223 { |
224 assert(index_.currentStorageSize_ == index_.db_->GetTotalCompressedSize()); | 224 assert(index_.currentStorageSize_ == index_.db_.GetTotalCompressedSize()); |
225 | 225 |
226 transaction_.reset(index_.db_->StartTransaction()); | 226 transaction_.reset(index_.db_.StartTransaction()); |
227 transaction_->Begin(); | 227 transaction_->Begin(); |
228 | 228 |
229 index_.listener_->StartTransaction(); | 229 index_.listener_->StartTransaction(); |
230 } | 230 } |
231 | 231 |
248 index_.currentStorageSize_ += sizeOfAddedFiles; | 248 index_.currentStorageSize_ += sizeOfAddedFiles; |
249 | 249 |
250 assert(index_.currentStorageSize_ >= index_.listener_->GetSizeOfFilesToRemove()); | 250 assert(index_.currentStorageSize_ >= index_.listener_->GetSizeOfFilesToRemove()); |
251 index_.currentStorageSize_ -= index_.listener_->GetSizeOfFilesToRemove(); | 251 index_.currentStorageSize_ -= index_.listener_->GetSizeOfFilesToRemove(); |
252 | 252 |
253 assert(index_.currentStorageSize_ == index_.db_->GetTotalCompressedSize()); | 253 assert(index_.currentStorageSize_ == index_.db_.GetTotalCompressedSize()); |
254 | 254 |
255 // Send all the pending changes to the Orthanc plugins | 255 // Send all the pending changes to the Orthanc plugins |
256 index_.listener_->CommitChanges(); | 256 index_.listener_->CommitChanges(); |
257 | 257 |
258 isCommitted_ = true; | 258 isCommitted_ = true; |
306 | 306 |
307 Transaction t(*this); | 307 Transaction t(*this); |
308 | 308 |
309 int64_t id; | 309 int64_t id; |
310 ResourceType type; | 310 ResourceType type; |
311 if (!db_->LookupResource(uuid, id, type) || | 311 if (!db_.LookupResource(uuid, id, type) || |
312 expectedType != type) | 312 expectedType != type) |
313 { | 313 { |
314 return false; | 314 return false; |
315 } | 315 } |
316 | 316 |
317 db_->DeleteResource(id); | 317 db_.DeleteResource(id); |
318 | 318 |
319 if (listener_->HasRemainingLevel()) | 319 if (listener_->HasRemainingLevel()) |
320 { | 320 { |
321 ResourceType type = listener_->GetRemainingType(); | 321 ResourceType type = listener_->GetRemainingType(); |
322 const std::string& uuid = listener_->GetRemainingPublicId(); | 322 const std::string& uuid = listener_->GetRemainingPublicId(); |
345 try | 345 try |
346 { | 346 { |
347 boost::mutex::scoped_lock lock(that->mutex_); | 347 boost::mutex::scoped_lock lock(that->mutex_); |
348 std::string sleepString; | 348 std::string sleepString; |
349 | 349 |
350 if (that->db_->LookupGlobalProperty(sleepString, GlobalProperty_FlushSleep) && | 350 if (that->db_.LookupGlobalProperty(sleepString, GlobalProperty_FlushSleep) && |
351 Toolbox::IsInteger(sleepString)) | 351 Toolbox::IsInteger(sleepString)) |
352 { | 352 { |
353 sleep = boost::lexical_cast<unsigned int>(sleepString); | 353 sleep = boost::lexical_cast<unsigned int>(sleepString); |
354 } | 354 } |
355 } | 355 } |
369 { | 369 { |
370 continue; | 370 continue; |
371 } | 371 } |
372 | 372 |
373 boost::mutex::scoped_lock lock(that->mutex_); | 373 boost::mutex::scoped_lock lock(that->mutex_); |
374 that->db_->FlushToDisk(); | 374 that->db_.FlushToDisk(); |
375 count = 0; | 375 count = 0; |
376 } | 376 } |
377 | 377 |
378 LOG(INFO) << "Stopping the database flushing thread"; | 378 LOG(INFO) << "Stopping the database flushing thread"; |
379 } | 379 } |
380 | 380 |
381 | 381 |
382 static void ComputeExpectedNumberOfInstances(DatabaseWrapper& db, | 382 static void ComputeExpectedNumberOfInstances(IDatabaseWrapper& db, |
383 int64_t series, | 383 int64_t series, |
384 const DicomMap& dicomSummary) | 384 const DicomMap& dicomSummary) |
385 { | 385 { |
386 try | 386 try |
387 { | 387 { |
424 bool ServerIndex::GetMetadataAsInteger(int64_t& result, | 424 bool ServerIndex::GetMetadataAsInteger(int64_t& result, |
425 int64_t id, | 425 int64_t id, |
426 MetadataType type) | 426 MetadataType type) |
427 { | 427 { |
428 std::string s; | 428 std::string s; |
429 if (!db_->LookupMetadata(s, id, type)) | 429 if (!db_.LookupMetadata(s, id, type)) |
430 { | 430 { |
431 return false; | 431 return false; |
432 } | 432 } |
433 | 433 |
434 try | 434 try |
446 | 446 |
447 uint64_t ServerIndex::IncrementGlobalSequenceInternal(GlobalProperty property) | 447 uint64_t ServerIndex::IncrementGlobalSequenceInternal(GlobalProperty property) |
448 { | 448 { |
449 std::string oldValue; | 449 std::string oldValue; |
450 | 450 |
451 if (db_->LookupGlobalProperty(oldValue, property)) | 451 if (db_.LookupGlobalProperty(oldValue, property)) |
452 { | 452 { |
453 uint64_t oldNumber; | 453 uint64_t oldNumber; |
454 | 454 |
455 try | 455 try |
456 { | 456 { |
457 oldNumber = boost::lexical_cast<uint64_t>(oldValue); | 457 oldNumber = boost::lexical_cast<uint64_t>(oldValue); |
458 db_->SetGlobalProperty(property, boost::lexical_cast<std::string>(oldNumber + 1)); | 458 db_.SetGlobalProperty(property, boost::lexical_cast<std::string>(oldNumber + 1)); |
459 return oldNumber + 1; | 459 return oldNumber + 1; |
460 } | 460 } |
461 catch (boost::bad_lexical_cast&) | 461 catch (boost::bad_lexical_cast&) |
462 { | 462 { |
463 throw OrthancException(ErrorCode_InternalError); | 463 throw OrthancException(ErrorCode_InternalError); |
464 } | 464 } |
465 } | 465 } |
466 else | 466 else |
467 { | 467 { |
468 // Initialize the sequence at "1" | 468 // Initialize the sequence at "1" |
469 db_->SetGlobalProperty(property, "1"); | 469 db_.SetGlobalProperty(property, "1"); |
470 return 1; | 470 return 1; |
471 } | 471 } |
472 } | 472 } |
473 | 473 |
474 | 474 |
475 | 475 |
476 ServerIndex::ServerIndex(ServerContext& context, | 476 ServerIndex::ServerIndex(ServerContext& context, |
477 const std::string& dbPath) : | 477 IDatabaseWrapper& db) : |
478 done_(false), | 478 done_(false), |
479 db_(db), | |
479 maximumStorageSize_(0), | 480 maximumStorageSize_(0), |
480 maximumPatients_(0) | 481 maximumPatients_(0) |
481 { | 482 { |
482 listener_.reset(new Internals::ServerIndexListener(context)); | 483 listener_.reset(new Internals::ServerIndexListener(context)); |
483 | 484 db_.SetListener(*listener_); |
484 if (dbPath == ":memory:") | 485 |
485 { | 486 currentStorageSize_ = db_.GetTotalCompressedSize(); |
486 db_.reset(new DatabaseWrapper(*listener_)); | |
487 } | |
488 else | |
489 { | |
490 boost::filesystem::path p = dbPath; | |
491 | |
492 try | |
493 { | |
494 boost::filesystem::create_directories(p); | |
495 } | |
496 catch (boost::filesystem::filesystem_error) | |
497 { | |
498 } | |
499 | |
500 db_.reset(new DatabaseWrapper(p.string() + "/index", *listener_)); | |
501 } | |
502 | |
503 currentStorageSize_ = db_->GetTotalCompressedSize(); | |
504 | 487 |
505 // Initial recycling if the parameters have changed since the last | 488 // Initial recycling if the parameters have changed since the last |
506 // execution of Orthanc | 489 // execution of Orthanc |
507 StandaloneRecycling(); | 490 StandaloneRecycling(); |
508 | 491 |
545 | 528 |
546 // Do nothing if the instance already exists | 529 // Do nothing if the instance already exists |
547 { | 530 { |
548 ResourceType type; | 531 ResourceType type; |
549 int64_t tmp; | 532 int64_t tmp; |
550 if (db_->LookupResource(hasher.HashInstance(), tmp, type)) | 533 if (db_.LookupResource(hasher.HashInstance(), tmp, type)) |
551 { | 534 { |
552 assert(type == ResourceType_Instance); | 535 assert(type == ResourceType_Instance); |
553 db_->GetAllMetadata(instanceMetadata, tmp); | 536 db_.GetAllMetadata(instanceMetadata, tmp); |
554 return StoreStatus_AlreadyStored; | 537 return StoreStatus_AlreadyStored; |
555 } | 538 } |
556 } | 539 } |
557 | 540 |
558 // Ensure there is enough room in the storage for the new instance | 541 // Ensure there is enough room in the storage for the new instance |
564 } | 547 } |
565 | 548 |
566 Recycle(instanceSize, hasher.HashPatient()); | 549 Recycle(instanceSize, hasher.HashPatient()); |
567 | 550 |
568 // Create the instance | 551 // Create the instance |
569 int64_t instance = db_->CreateResource(hasher.HashInstance(), ResourceType_Instance); | 552 int64_t instance = db_.CreateResource(hasher.HashInstance(), ResourceType_Instance); |
570 | 553 |
571 DicomMap dicom; | 554 DicomMap dicom; |
572 dicomSummary.ExtractInstanceInformation(dicom); | 555 dicomSummary.ExtractInstanceInformation(dicom); |
573 db_->SetMainDicomTags(instance, dicom); | 556 db_.SetMainDicomTags(instance, dicom); |
574 | 557 |
575 // Detect up to which level the patient/study/series/instance | 558 // Detect up to which level the patient/study/series/instance |
576 // hierarchy must be created | 559 // hierarchy must be created |
577 int64_t patient = -1, study = -1, series = -1; | 560 int64_t patient = -1, study = -1, series = -1; |
578 bool isNewPatient = false; | 561 bool isNewPatient = false; |
580 bool isNewSeries = false; | 563 bool isNewSeries = false; |
581 | 564 |
582 { | 565 { |
583 ResourceType dummy; | 566 ResourceType dummy; |
584 | 567 |
585 if (db_->LookupResource(hasher.HashSeries(), series, dummy)) | 568 if (db_.LookupResource(hasher.HashSeries(), series, dummy)) |
586 { | 569 { |
587 assert(dummy == ResourceType_Series); | 570 assert(dummy == ResourceType_Series); |
588 // The patient, the study and the series already exist | 571 // The patient, the study and the series already exist |
589 | 572 |
590 bool ok = (db_->LookupResource(hasher.HashPatient(), patient, dummy) && | 573 bool ok = (db_.LookupResource(hasher.HashPatient(), patient, dummy) && |
591 db_->LookupResource(hasher.HashStudy(), study, dummy)); | 574 db_.LookupResource(hasher.HashStudy(), study, dummy)); |
592 assert(ok); | 575 assert(ok); |
593 } | 576 } |
594 else if (db_->LookupResource(hasher.HashStudy(), study, dummy)) | 577 else if (db_.LookupResource(hasher.HashStudy(), study, dummy)) |
595 { | 578 { |
596 assert(dummy == ResourceType_Study); | 579 assert(dummy == ResourceType_Study); |
597 | 580 |
598 // New series: The patient and the study already exist | 581 // New series: The patient and the study already exist |
599 isNewSeries = true; | 582 isNewSeries = true; |
600 | 583 |
601 bool ok = db_->LookupResource(hasher.HashPatient(), patient, dummy); | 584 bool ok = db_.LookupResource(hasher.HashPatient(), patient, dummy); |
602 assert(ok); | 585 assert(ok); |
603 } | 586 } |
604 else if (db_->LookupResource(hasher.HashPatient(), patient, dummy)) | 587 else if (db_.LookupResource(hasher.HashPatient(), patient, dummy)) |
605 { | 588 { |
606 assert(dummy == ResourceType_Patient); | 589 assert(dummy == ResourceType_Patient); |
607 | 590 |
608 // New study and series: The patient already exist | 591 // New study and series: The patient already exist |
609 isNewStudy = true; | 592 isNewStudy = true; |
619 } | 602 } |
620 | 603 |
621 // Create the series if needed | 604 // Create the series if needed |
622 if (isNewSeries) | 605 if (isNewSeries) |
623 { | 606 { |
624 series = db_->CreateResource(hasher.HashSeries(), ResourceType_Series); | 607 series = db_.CreateResource(hasher.HashSeries(), ResourceType_Series); |
625 dicomSummary.ExtractSeriesInformation(dicom); | 608 dicomSummary.ExtractSeriesInformation(dicom); |
626 db_->SetMainDicomTags(series, dicom); | 609 db_.SetMainDicomTags(series, dicom); |
627 } | 610 } |
628 | 611 |
629 // Create the study if needed | 612 // Create the study if needed |
630 if (isNewStudy) | 613 if (isNewStudy) |
631 { | 614 { |
632 study = db_->CreateResource(hasher.HashStudy(), ResourceType_Study); | 615 study = db_.CreateResource(hasher.HashStudy(), ResourceType_Study); |
633 dicomSummary.ExtractStudyInformation(dicom); | 616 dicomSummary.ExtractStudyInformation(dicom); |
634 db_->SetMainDicomTags(study, dicom); | 617 db_.SetMainDicomTags(study, dicom); |
635 } | 618 } |
636 | 619 |
637 // Create the patient if needed | 620 // Create the patient if needed |
638 if (isNewPatient) | 621 if (isNewPatient) |
639 { | 622 { |
640 patient = db_->CreateResource(hasher.HashPatient(), ResourceType_Patient); | 623 patient = db_.CreateResource(hasher.HashPatient(), ResourceType_Patient); |
641 dicomSummary.ExtractPatientInformation(dicom); | 624 dicomSummary.ExtractPatientInformation(dicom); |
642 db_->SetMainDicomTags(patient, dicom); | 625 db_.SetMainDicomTags(patient, dicom); |
643 } | 626 } |
644 | 627 |
645 // Create the parent-to-child links | 628 // Create the parent-to-child links |
646 db_->AttachChild(series, instance); | 629 db_.AttachChild(series, instance); |
647 | 630 |
648 if (isNewSeries) | 631 if (isNewSeries) |
649 { | 632 { |
650 db_->AttachChild(study, series); | 633 db_.AttachChild(study, series); |
651 } | 634 } |
652 | 635 |
653 if (isNewStudy) | 636 if (isNewStudy) |
654 { | 637 { |
655 db_->AttachChild(patient, study); | 638 db_.AttachChild(patient, study); |
656 } | 639 } |
657 | 640 |
658 // Sanity checks | 641 // Sanity checks |
659 assert(patient != -1); | 642 assert(patient != -1); |
660 assert(study != -1); | 643 assert(study != -1); |
663 | 646 |
664 // Attach the files to the newly created instance | 647 // Attach the files to the newly created instance |
665 for (Attachments::const_iterator it = attachments.begin(); | 648 for (Attachments::const_iterator it = attachments.begin(); |
666 it != attachments.end(); ++it) | 649 it != attachments.end(); ++it) |
667 { | 650 { |
668 db_->AddAttachment(instance, *it); | 651 db_.AddAttachment(instance, *it); |
669 } | 652 } |
670 | 653 |
671 // Attach the user-specified metadata | 654 // Attach the user-specified metadata |
672 for (MetadataMap::const_iterator | 655 for (MetadataMap::const_iterator |
673 it = metadata.begin(); it != metadata.end(); ++it) | 656 it = metadata.begin(); it != metadata.end(); ++it) |
674 { | 657 { |
675 switch (it->first.first) | 658 switch (it->first.first) |
676 { | 659 { |
677 case ResourceType_Patient: | 660 case ResourceType_Patient: |
678 db_->SetMetadata(patient, it->first.second, it->second); | 661 db_.SetMetadata(patient, it->first.second, it->second); |
679 break; | 662 break; |
680 | 663 |
681 case ResourceType_Study: | 664 case ResourceType_Study: |
682 db_->SetMetadata(study, it->first.second, it->second); | 665 db_.SetMetadata(study, it->first.second, it->second); |
683 break; | 666 break; |
684 | 667 |
685 case ResourceType_Series: | 668 case ResourceType_Series: |
686 db_->SetMetadata(series, it->first.second, it->second); | 669 db_.SetMetadata(series, it->first.second, it->second); |
687 break; | 670 break; |
688 | 671 |
689 case ResourceType_Instance: | 672 case ResourceType_Instance: |
690 db_->SetMetadata(instance, it->first.second, it->second); | 673 db_.SetMetadata(instance, it->first.second, it->second); |
691 instanceMetadata[it->first.second] = it->second; | 674 instanceMetadata[it->first.second] = it->second; |
692 break; | 675 break; |
693 | 676 |
694 default: | 677 default: |
695 throw OrthancException(ErrorCode_ParameterOutOfRange); | 678 throw OrthancException(ErrorCode_ParameterOutOfRange); |
696 } | 679 } |
697 } | 680 } |
698 | 681 |
699 // Attach the auto-computed metadata for the patient/study/series levels | 682 // Attach the auto-computed metadata for the patient/study/series levels |
700 std::string now = Toolbox::GetNowIsoString(); | 683 std::string now = Toolbox::GetNowIsoString(); |
701 db_->SetMetadata(series, MetadataType_LastUpdate, now); | 684 db_.SetMetadata(series, MetadataType_LastUpdate, now); |
702 db_->SetMetadata(study, MetadataType_LastUpdate, now); | 685 db_.SetMetadata(study, MetadataType_LastUpdate, now); |
703 db_->SetMetadata(patient, MetadataType_LastUpdate, now); | 686 db_.SetMetadata(patient, MetadataType_LastUpdate, now); |
704 | 687 |
705 // Attach the auto-computed metadata for the instance level, | 688 // Attach the auto-computed metadata for the instance level, |
706 // reflecting these additions into the input metadata map | 689 // reflecting these additions into the input metadata map |
707 db_->SetMetadata(instance, MetadataType_Instance_ReceptionDate, now); | 690 db_.SetMetadata(instance, MetadataType_Instance_ReceptionDate, now); |
708 instanceMetadata[MetadataType_Instance_ReceptionDate] = now; | 691 instanceMetadata[MetadataType_Instance_ReceptionDate] = now; |
709 | 692 |
710 db_->SetMetadata(instance, MetadataType_Instance_RemoteAet, remoteAet); | 693 db_.SetMetadata(instance, MetadataType_Instance_RemoteAet, remoteAet); |
711 instanceMetadata[MetadataType_Instance_RemoteAet] = remoteAet; | 694 instanceMetadata[MetadataType_Instance_RemoteAet] = remoteAet; |
712 | 695 |
713 const DicomValue* value; | 696 const DicomValue* value; |
714 if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_INSTANCE_NUMBER)) != NULL || | 697 if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_INSTANCE_NUMBER)) != NULL || |
715 (value = dicomSummary.TestAndGetValue(DICOM_TAG_IMAGE_INDEX)) != NULL) | 698 (value = dicomSummary.TestAndGetValue(DICOM_TAG_IMAGE_INDEX)) != NULL) |
716 { | 699 { |
717 db_->SetMetadata(instance, MetadataType_Instance_IndexInSeries, value->AsString()); | 700 db_.SetMetadata(instance, MetadataType_Instance_IndexInSeries, value->AsString()); |
718 instanceMetadata[MetadataType_Instance_IndexInSeries] = value->AsString(); | 701 instanceMetadata[MetadataType_Instance_IndexInSeries] = value->AsString(); |
719 } | 702 } |
720 | 703 |
721 // Check whether the series of this new instance is now completed | 704 // Check whether the series of this new instance is now completed |
722 if (isNewSeries) | 705 if (isNewSeries) |
723 { | 706 { |
724 ComputeExpectedNumberOfInstances(*db_, series, dicomSummary); | 707 ComputeExpectedNumberOfInstances(db_, series, dicomSummary); |
725 } | 708 } |
726 | 709 |
727 SeriesStatus seriesStatus = GetSeriesStatus(series); | 710 SeriesStatus seriesStatus = GetSeriesStatus(series); |
728 if (seriesStatus == SeriesStatus_Complete) | 711 if (seriesStatus == SeriesStatus_Complete) |
729 { | 712 { |
739 | 722 |
740 return StoreStatus_Success; | 723 return StoreStatus_Success; |
741 } | 724 } |
742 catch (OrthancException& e) | 725 catch (OrthancException& e) |
743 { | 726 { |
744 LOG(ERROR) << "EXCEPTION [" << e.What() << "]" | 727 LOG(ERROR) << "EXCEPTION [" << e.What() << "]"; |
745 << " (SQLite status: " << db_->GetErrorMessage() << ")"; | |
746 } | 728 } |
747 | 729 |
748 return StoreStatus_Failure; | 730 return StoreStatus_Failure; |
749 } | 731 } |
750 | 732 |
753 { | 735 { |
754 boost::mutex::scoped_lock lock(mutex_); | 736 boost::mutex::scoped_lock lock(mutex_); |
755 target = Json::objectValue; | 737 target = Json::objectValue; |
756 | 738 |
757 uint64_t cs = currentStorageSize_; | 739 uint64_t cs = currentStorageSize_; |
758 assert(cs == db_->GetTotalCompressedSize()); | 740 assert(cs == db_.GetTotalCompressedSize()); |
759 uint64_t us = db_->GetTotalUncompressedSize(); | 741 uint64_t us = db_.GetTotalUncompressedSize(); |
760 target["TotalDiskSize"] = boost::lexical_cast<std::string>(cs); | 742 target["TotalDiskSize"] = boost::lexical_cast<std::string>(cs); |
761 target["TotalUncompressedSize"] = boost::lexical_cast<std::string>(us); | 743 target["TotalUncompressedSize"] = boost::lexical_cast<std::string>(us); |
762 target["TotalDiskSizeMB"] = boost::lexical_cast<unsigned int>(cs / MEGA_BYTES); | 744 target["TotalDiskSizeMB"] = boost::lexical_cast<unsigned int>(cs / MEGA_BYTES); |
763 target["TotalUncompressedSizeMB"] = boost::lexical_cast<unsigned int>(us / MEGA_BYTES); | 745 target["TotalUncompressedSizeMB"] = boost::lexical_cast<unsigned int>(us / MEGA_BYTES); |
764 | 746 |
765 target["CountPatients"] = static_cast<unsigned int>(db_->GetResourceCount(ResourceType_Patient)); | 747 target["CountPatients"] = static_cast<unsigned int>(db_.GetResourceCount(ResourceType_Patient)); |
766 target["CountStudies"] = static_cast<unsigned int>(db_->GetResourceCount(ResourceType_Study)); | 748 target["CountStudies"] = static_cast<unsigned int>(db_.GetResourceCount(ResourceType_Study)); |
767 target["CountSeries"] = static_cast<unsigned int>(db_->GetResourceCount(ResourceType_Series)); | 749 target["CountSeries"] = static_cast<unsigned int>(db_.GetResourceCount(ResourceType_Series)); |
768 target["CountInstances"] = static_cast<unsigned int>(db_->GetResourceCount(ResourceType_Instance)); | 750 target["CountInstances"] = static_cast<unsigned int>(db_.GetResourceCount(ResourceType_Instance)); |
769 } | 751 } |
770 | 752 |
771 | 753 |
772 | 754 |
773 SeriesStatus ServerIndex::GetSeriesStatus(int64_t id) | 755 SeriesStatus ServerIndex::GetSeriesStatus(int64_t id) |
779 return SeriesStatus_Unknown; | 761 return SeriesStatus_Unknown; |
780 } | 762 } |
781 | 763 |
782 // Loop over the instances of this series | 764 // Loop over the instances of this series |
783 std::list<int64_t> children; | 765 std::list<int64_t> children; |
784 db_->GetChildrenInternalId(children, id); | 766 db_.GetChildrenInternalId(children, id); |
785 | 767 |
786 std::set<int64_t> instances; | 768 std::set<int64_t> instances; |
787 for (std::list<int64_t>::const_iterator | 769 for (std::list<int64_t>::const_iterator |
788 it = children.begin(); it != children.end(); ++it) | 770 it = children.begin(); it != children.end(); ++it) |
789 { | 771 { |
823 | 805 |
824 void ServerIndex::MainDicomTagsToJson(Json::Value& target, | 806 void ServerIndex::MainDicomTagsToJson(Json::Value& target, |
825 int64_t resourceId) | 807 int64_t resourceId) |
826 { | 808 { |
827 DicomMap tags; | 809 DicomMap tags; |
828 db_->GetMainDicomTags(tags, resourceId); | 810 db_.GetMainDicomTags(tags, resourceId); |
829 target["MainDicomTags"] = Json::objectValue; | 811 target["MainDicomTags"] = Json::objectValue; |
830 FromDcmtkBridge::ToJson(target["MainDicomTags"], tags); | 812 FromDcmtkBridge::ToJson(target["MainDicomTags"], tags); |
831 } | 813 } |
832 | 814 |
833 bool ServerIndex::LookupResource(Json::Value& result, | 815 bool ServerIndex::LookupResource(Json::Value& result, |
839 boost::mutex::scoped_lock lock(mutex_); | 821 boost::mutex::scoped_lock lock(mutex_); |
840 | 822 |
841 // Lookup for the requested resource | 823 // Lookup for the requested resource |
842 int64_t id; | 824 int64_t id; |
843 ResourceType type; | 825 ResourceType type; |
844 if (!db_->LookupResource(publicId, id, type) || | 826 if (!db_.LookupResource(publicId, id, type) || |
845 type != expectedType) | 827 type != expectedType) |
846 { | 828 { |
847 return false; | 829 return false; |
848 } | 830 } |
849 | 831 |
850 // Find the parent resource (if it exists) | 832 // Find the parent resource (if it exists) |
851 if (type != ResourceType_Patient) | 833 if (type != ResourceType_Patient) |
852 { | 834 { |
853 int64_t parentId; | 835 int64_t parentId; |
854 if (!db_->LookupParent(parentId, id)) | 836 if (!db_.LookupParent(parentId, id)) |
855 { | 837 { |
856 throw OrthancException(ErrorCode_InternalError); | 838 throw OrthancException(ErrorCode_InternalError); |
857 } | 839 } |
858 | 840 |
859 std::string parent = db_->GetPublicId(parentId); | 841 std::string parent = db_.GetPublicId(parentId); |
860 | 842 |
861 switch (type) | 843 switch (type) |
862 { | 844 { |
863 case ResourceType_Study: | 845 case ResourceType_Study: |
864 result["ParentPatient"] = parent; | 846 result["ParentPatient"] = parent; |
877 } | 859 } |
878 } | 860 } |
879 | 861 |
880 // List the children resources | 862 // List the children resources |
881 std::list<std::string> children; | 863 std::list<std::string> children; |
882 db_->GetChildrenPublicId(children, id); | 864 db_.GetChildrenPublicId(children, id); |
883 | 865 |
884 if (type != ResourceType_Instance) | 866 if (type != ResourceType_Instance) |
885 { | 867 { |
886 Json::Value c = Json::arrayValue; | 868 Json::Value c = Json::arrayValue; |
887 | 869 |
938 case ResourceType_Instance: | 920 case ResourceType_Instance: |
939 { | 921 { |
940 result["Type"] = "Instance"; | 922 result["Type"] = "Instance"; |
941 | 923 |
942 FileInfo attachment; | 924 FileInfo attachment; |
943 if (!db_->LookupAttachment(attachment, id, FileContentType_Dicom)) | 925 if (!db_.LookupAttachment(attachment, id, FileContentType_Dicom)) |
944 { | 926 { |
945 throw OrthancException(ErrorCode_InternalError); | 927 throw OrthancException(ErrorCode_InternalError); |
946 } | 928 } |
947 | 929 |
948 result["FileSize"] = static_cast<unsigned int>(attachment.GetUncompressedSize()); | 930 result["FileSize"] = static_cast<unsigned int>(attachment.GetUncompressedSize()); |
965 result["ID"] = publicId; | 947 result["ID"] = publicId; |
966 MainDicomTagsToJson(result, id); | 948 MainDicomTagsToJson(result, id); |
967 | 949 |
968 std::string tmp; | 950 std::string tmp; |
969 | 951 |
970 if (db_->LookupMetadata(tmp, id, MetadataType_AnonymizedFrom)) | 952 if (db_.LookupMetadata(tmp, id, MetadataType_AnonymizedFrom)) |
971 { | 953 { |
972 result["AnonymizedFrom"] = tmp; | 954 result["AnonymizedFrom"] = tmp; |
973 } | 955 } |
974 | 956 |
975 if (db_->LookupMetadata(tmp, id, MetadataType_ModifiedFrom)) | 957 if (db_.LookupMetadata(tmp, id, MetadataType_ModifiedFrom)) |
976 { | 958 { |
977 result["ModifiedFrom"] = tmp; | 959 result["ModifiedFrom"] = tmp; |
978 } | 960 } |
979 | 961 |
980 if (type == ResourceType_Patient || | 962 if (type == ResourceType_Patient || |
981 type == ResourceType_Study || | 963 type == ResourceType_Study || |
982 type == ResourceType_Series) | 964 type == ResourceType_Series) |
983 { | 965 { |
984 result["IsStable"] = !unstableResources_.Contains(id); | 966 result["IsStable"] = !unstableResources_.Contains(id); |
985 | 967 |
986 if (db_->LookupMetadata(tmp, id, MetadataType_LastUpdate)) | 968 if (db_.LookupMetadata(tmp, id, MetadataType_LastUpdate)) |
987 { | 969 { |
988 result["LastUpdate"] = tmp; | 970 result["LastUpdate"] = tmp; |
989 } | 971 } |
990 } | 972 } |
991 | 973 |
999 { | 981 { |
1000 boost::mutex::scoped_lock lock(mutex_); | 982 boost::mutex::scoped_lock lock(mutex_); |
1001 | 983 |
1002 int64_t id; | 984 int64_t id; |
1003 ResourceType type; | 985 ResourceType type; |
1004 if (!db_->LookupResource(instanceUuid, id, type)) | 986 if (!db_.LookupResource(instanceUuid, id, type)) |
1005 { | 987 { |
1006 throw OrthancException(ErrorCode_UnknownResource); | 988 throw OrthancException(ErrorCode_UnknownResource); |
1007 } | 989 } |
1008 | 990 |
1009 if (db_->LookupAttachment(attachment, id, contentType)) | 991 if (db_.LookupAttachment(attachment, id, contentType)) |
1010 { | 992 { |
1011 assert(attachment.GetContentType() == contentType); | 993 assert(attachment.GetContentType() == contentType); |
1012 return true; | 994 return true; |
1013 } | 995 } |
1014 else | 996 else |
1024 { | 1006 { |
1025 std::list<std::string> lst; | 1007 std::list<std::string> lst; |
1026 | 1008 |
1027 { | 1009 { |
1028 boost::mutex::scoped_lock lock(mutex_); | 1010 boost::mutex::scoped_lock lock(mutex_); |
1029 db_->GetAllPublicIds(lst, resourceType); | 1011 db_.GetAllPublicIds(lst, resourceType); |
1030 } | 1012 } |
1031 | 1013 |
1032 target = Json::arrayValue; | 1014 target = Json::arrayValue; |
1033 for (std::list<std::string>::const_iterator | 1015 for (std::list<std::string>::const_iterator |
1034 it = lst.begin(); it != lst.end(); it++) | 1016 it = lst.begin(); it != lst.end(); it++) |
1061 int64_t last = (log.size() == 0 ? since : log.back().GetSeq()); | 1043 int64_t last = (log.size() == 0 ? since : log.back().GetSeq()); |
1062 target["Last"] = static_cast<int>(last); | 1044 target["Last"] = static_cast<int>(last); |
1063 } | 1045 } |
1064 | 1046 |
1065 | 1047 |
1066 bool ServerIndex::GetChanges(Json::Value& target, | 1048 void ServerIndex::GetChanges(Json::Value& target, |
1067 int64_t since, | 1049 int64_t since, |
1068 unsigned int maxResults) | 1050 unsigned int maxResults) |
1069 { | 1051 { |
1070 std::list<ServerIndexChange> changes; | 1052 std::list<ServerIndexChange> changes; |
1071 bool done; | 1053 bool done; |
1072 | 1054 |
1073 { | 1055 { |
1074 boost::mutex::scoped_lock lock(mutex_); | 1056 boost::mutex::scoped_lock lock(mutex_); |
1075 db_->GetChanges(changes, done, since, maxResults); | 1057 db_.GetChanges(changes, done, since, maxResults); |
1076 } | 1058 } |
1077 | 1059 |
1078 FormatLog(target, changes, "Changes", done, since); | 1060 FormatLog(target, changes, "Changes", done, since); |
1079 return true; | 1061 } |
1080 } | 1062 |
1081 | 1063 |
1082 | 1064 void ServerIndex::GetLastChange(Json::Value& target) |
1083 bool ServerIndex::GetLastChange(Json::Value& target) | |
1084 { | 1065 { |
1085 std::list<ServerIndexChange> changes; | 1066 std::list<ServerIndexChange> changes; |
1086 | 1067 |
1087 { | 1068 { |
1088 boost::mutex::scoped_lock lock(mutex_); | 1069 boost::mutex::scoped_lock lock(mutex_); |
1089 db_->GetLastChange(changes); | 1070 db_.GetLastChange(changes); |
1090 } | 1071 } |
1091 | 1072 |
1092 FormatLog(target, changes, "Changes", true, 0); | 1073 FormatLog(target, changes, "Changes", true, 0); |
1093 return true; | |
1094 } | 1074 } |
1095 | 1075 |
1096 | 1076 |
1097 void ServerIndex::LogExportedResource(const std::string& publicId, | 1077 void ServerIndex::LogExportedResource(const std::string& publicId, |
1098 const std::string& remoteModality) | 1078 const std::string& remoteModality) |
1099 { | 1079 { |
1100 boost::mutex::scoped_lock lock(mutex_); | 1080 boost::mutex::scoped_lock lock(mutex_); |
1101 | 1081 |
1102 int64_t id; | 1082 int64_t id; |
1103 ResourceType type; | 1083 ResourceType type; |
1104 if (!db_->LookupResource(publicId, id, type)) | 1084 if (!db_.LookupResource(publicId, id, type)) |
1105 { | 1085 { |
1106 throw OrthancException(ErrorCode_InternalError); | 1086 throw OrthancException(ErrorCode_InternalError); |
1107 } | 1087 } |
1108 | 1088 |
1109 std::string patientId; | 1089 std::string patientId; |
1117 // Iteratively go up inside the patient/study/series/instance hierarchy | 1097 // Iteratively go up inside the patient/study/series/instance hierarchy |
1118 bool done = false; | 1098 bool done = false; |
1119 while (!done) | 1099 while (!done) |
1120 { | 1100 { |
1121 DicomMap map; | 1101 DicomMap map; |
1122 db_->GetMainDicomTags(map, currentId); | 1102 db_.GetMainDicomTags(map, currentId); |
1123 | 1103 |
1124 switch (currentType) | 1104 switch (currentType) |
1125 { | 1105 { |
1126 case ResourceType_Patient: | 1106 case ResourceType_Patient: |
1127 patientId = map.GetValue(DICOM_TAG_PATIENT_ID).AsString(); | 1107 patientId = map.GetValue(DICOM_TAG_PATIENT_ID).AsString(); |
1149 | 1129 |
1150 // If we have not reached the Patient level, find the parent of | 1130 // If we have not reached the Patient level, find the parent of |
1151 // the current resource | 1131 // the current resource |
1152 if (!done) | 1132 if (!done) |
1153 { | 1133 { |
1154 bool ok = db_->LookupParent(currentId, currentId); | 1134 bool ok = db_.LookupParent(currentId, currentId); |
1155 assert(ok); | 1135 assert(ok); |
1156 } | 1136 } |
1157 } | 1137 } |
1158 | 1138 |
1159 // No need for a SQLite::ITransaction here, as we only insert 1 record | 1139 // No need for a SQLite::ITransaction here, as we only insert 1 record |
1164 Toolbox::GetNowIsoString(), | 1144 Toolbox::GetNowIsoString(), |
1165 patientId, | 1145 patientId, |
1166 studyInstanceUid, | 1146 studyInstanceUid, |
1167 seriesInstanceUid, | 1147 seriesInstanceUid, |
1168 sopInstanceUid); | 1148 sopInstanceUid); |
1169 db_->LogExportedResource(resource); | 1149 db_.LogExportedResource(resource); |
1170 } | 1150 } |
1171 | 1151 |
1172 | 1152 |
1173 bool ServerIndex::GetExportedResources(Json::Value& target, | 1153 void ServerIndex::GetExportedResources(Json::Value& target, |
1174 int64_t since, | 1154 int64_t since, |
1175 unsigned int maxResults) | 1155 unsigned int maxResults) |
1176 { | 1156 { |
1177 std::list<ExportedResource> exported; | 1157 std::list<ExportedResource> exported; |
1178 bool done; | 1158 bool done; |
1179 | 1159 |
1180 { | 1160 { |
1181 boost::mutex::scoped_lock lock(mutex_); | 1161 boost::mutex::scoped_lock lock(mutex_); |
1182 db_->GetExportedResources(exported, done, since, maxResults); | 1162 db_.GetExportedResources(exported, done, since, maxResults); |
1183 } | 1163 } |
1184 | 1164 |
1185 FormatLog(target, exported, "Exports", done, since); | 1165 FormatLog(target, exported, "Exports", done, since); |
1186 return true; | 1166 } |
1187 } | 1167 |
1188 | 1168 |
1189 | 1169 void ServerIndex::GetLastExportedResource(Json::Value& target) |
1190 bool ServerIndex::GetLastExportedResource(Json::Value& target) | |
1191 { | 1170 { |
1192 std::list<ExportedResource> exported; | 1171 std::list<ExportedResource> exported; |
1193 | 1172 |
1194 { | 1173 { |
1195 boost::mutex::scoped_lock lock(mutex_); | 1174 boost::mutex::scoped_lock lock(mutex_); |
1196 db_->GetLastExportedResource(exported); | 1175 db_.GetLastExportedResource(exported); |
1197 } | 1176 } |
1198 | 1177 |
1199 FormatLog(target, exported, "Exports", true, 0); | 1178 FormatLog(target, exported, "Exports", true, 0); |
1200 return true; | |
1201 } | 1179 } |
1202 | 1180 |
1203 | 1181 |
1204 bool ServerIndex::IsRecyclingNeeded(uint64_t instanceSize) | 1182 bool ServerIndex::IsRecyclingNeeded(uint64_t instanceSize) |
1205 { | 1183 { |
1206 if (maximumStorageSize_ != 0) | 1184 if (maximumStorageSize_ != 0) |
1207 { | 1185 { |
1208 uint64_t currentSize = currentStorageSize_ - listener_->GetSizeOfFilesToRemove(); | 1186 uint64_t currentSize = currentStorageSize_ - listener_->GetSizeOfFilesToRemove(); |
1209 assert(db_->GetTotalCompressedSize() == currentSize); | 1187 assert(db_.GetTotalCompressedSize() == currentSize); |
1210 | 1188 |
1211 if (currentSize + instanceSize > maximumStorageSize_) | 1189 if (currentSize + instanceSize > maximumStorageSize_) |
1212 { | 1190 { |
1213 return true; | 1191 return true; |
1214 } | 1192 } |
1215 } | 1193 } |
1216 | 1194 |
1217 if (maximumPatients_ != 0) | 1195 if (maximumPatients_ != 0) |
1218 { | 1196 { |
1219 uint64_t patientCount = db_->GetResourceCount(ResourceType_Patient); | 1197 uint64_t patientCount = db_.GetResourceCount(ResourceType_Patient); |
1220 if (patientCount > maximumPatients_) | 1198 if (patientCount > maximumPatients_) |
1221 { | 1199 { |
1222 return true; | 1200 return true; |
1223 } | 1201 } |
1224 } | 1202 } |
1237 | 1215 |
1238 // Check whether other DICOM instances from this patient are | 1216 // Check whether other DICOM instances from this patient are |
1239 // already stored | 1217 // already stored |
1240 int64_t patientToAvoid; | 1218 int64_t patientToAvoid; |
1241 ResourceType type; | 1219 ResourceType type; |
1242 bool hasPatientToAvoid = db_->LookupResource(newPatientId, patientToAvoid, type); | 1220 bool hasPatientToAvoid = db_.LookupResource(newPatientId, patientToAvoid, type); |
1243 | 1221 |
1244 if (hasPatientToAvoid && type != ResourceType_Patient) | 1222 if (hasPatientToAvoid && type != ResourceType_Patient) |
1245 { | 1223 { |
1246 throw OrthancException(ErrorCode_InternalError); | 1224 throw OrthancException(ErrorCode_InternalError); |
1247 } | 1225 } |
1252 while (true) | 1230 while (true) |
1253 { | 1231 { |
1254 // If other instances of this patient are already in the store, | 1232 // If other instances of this patient are already in the store, |
1255 // we must avoid to recycle them | 1233 // we must avoid to recycle them |
1256 bool ok = hasPatientToAvoid ? | 1234 bool ok = hasPatientToAvoid ? |
1257 db_->SelectPatientToRecycle(patientToRecycle, patientToAvoid) : | 1235 db_.SelectPatientToRecycle(patientToRecycle, patientToAvoid) : |
1258 db_->SelectPatientToRecycle(patientToRecycle); | 1236 db_.SelectPatientToRecycle(patientToRecycle); |
1259 | 1237 |
1260 if (!ok) | 1238 if (!ok) |
1261 { | 1239 { |
1262 throw OrthancException(ErrorCode_FullStorage); | 1240 throw OrthancException(ErrorCode_FullStorage); |
1263 } | 1241 } |
1264 | 1242 |
1265 LOG(INFO) << "Recycling one patient"; | 1243 LOG(INFO) << "Recycling one patient"; |
1266 db_->DeleteResource(patientToRecycle); | 1244 db_.DeleteResource(patientToRecycle); |
1267 | 1245 |
1268 if (!IsRecyclingNeeded(instanceSize)) | 1246 if (!IsRecyclingNeeded(instanceSize)) |
1269 { | 1247 { |
1270 // OK, we're done | 1248 // OK, we're done |
1271 break; | 1249 break; |
1321 boost::mutex::scoped_lock lock(mutex_); | 1299 boost::mutex::scoped_lock lock(mutex_); |
1322 | 1300 |
1323 // Lookup for the requested resource | 1301 // Lookup for the requested resource |
1324 int64_t id; | 1302 int64_t id; |
1325 ResourceType type; | 1303 ResourceType type; |
1326 if (!db_->LookupResource(publicId, id, type) || | 1304 if (!db_.LookupResource(publicId, id, type) || |
1327 type != ResourceType_Patient) | 1305 type != ResourceType_Patient) |
1328 { | 1306 { |
1329 throw OrthancException(ErrorCode_ParameterOutOfRange); | 1307 throw OrthancException(ErrorCode_ParameterOutOfRange); |
1330 } | 1308 } |
1331 | 1309 |
1332 return db_->IsProtectedPatient(id); | 1310 return db_.IsProtectedPatient(id); |
1333 } | 1311 } |
1334 | 1312 |
1335 | 1313 |
1336 void ServerIndex::SetProtectedPatient(const std::string& publicId, | 1314 void ServerIndex::SetProtectedPatient(const std::string& publicId, |
1337 bool isProtected) | 1315 bool isProtected) |
1339 boost::mutex::scoped_lock lock(mutex_); | 1317 boost::mutex::scoped_lock lock(mutex_); |
1340 | 1318 |
1341 // Lookup for the requested resource | 1319 // Lookup for the requested resource |
1342 int64_t id; | 1320 int64_t id; |
1343 ResourceType type; | 1321 ResourceType type; |
1344 if (!db_->LookupResource(publicId, id, type) || | 1322 if (!db_.LookupResource(publicId, id, type) || |
1345 type != ResourceType_Patient) | 1323 type != ResourceType_Patient) |
1346 { | 1324 { |
1347 throw OrthancException(ErrorCode_ParameterOutOfRange); | 1325 throw OrthancException(ErrorCode_ParameterOutOfRange); |
1348 } | 1326 } |
1349 | 1327 |
1350 // No need for a SQLite::ITransaction here, as we only make 1 write to the DB | 1328 // No need for a SQLite::ITransaction here, as we only make 1 write to the DB |
1351 db_->SetProtectedPatient(id, isProtected); | 1329 db_.SetProtectedPatient(id, isProtected); |
1352 | 1330 |
1353 if (isProtected) | 1331 if (isProtected) |
1354 LOG(INFO) << "Patient " << publicId << " has been protected"; | 1332 LOG(INFO) << "Patient " << publicId << " has been protected"; |
1355 else | 1333 else |
1356 LOG(INFO) << "Patient " << publicId << " has been unprotected"; | 1334 LOG(INFO) << "Patient " << publicId << " has been unprotected"; |
1364 | 1342 |
1365 boost::mutex::scoped_lock lock(mutex_); | 1343 boost::mutex::scoped_lock lock(mutex_); |
1366 | 1344 |
1367 ResourceType type; | 1345 ResourceType type; |
1368 int64_t resource; | 1346 int64_t resource; |
1369 if (!db_->LookupResource(publicId, resource, type)) | 1347 if (!db_.LookupResource(publicId, resource, type)) |
1370 { | 1348 { |
1371 throw OrthancException(ErrorCode_UnknownResource); | 1349 throw OrthancException(ErrorCode_UnknownResource); |
1372 } | 1350 } |
1373 | 1351 |
1374 if (type == ResourceType_Instance) | 1352 if (type == ResourceType_Instance) |
1376 // An instance cannot have a child | 1354 // An instance cannot have a child |
1377 throw OrthancException(ErrorCode_BadParameterType); | 1355 throw OrthancException(ErrorCode_BadParameterType); |
1378 } | 1356 } |
1379 | 1357 |
1380 std::list<int64_t> tmp; | 1358 std::list<int64_t> tmp; |
1381 db_->GetChildrenInternalId(tmp, resource); | 1359 db_.GetChildrenInternalId(tmp, resource); |
1382 | 1360 |
1383 for (std::list<int64_t>::const_iterator | 1361 for (std::list<int64_t>::const_iterator |
1384 it = tmp.begin(); it != tmp.end(); ++it) | 1362 it = tmp.begin(); it != tmp.end(); ++it) |
1385 { | 1363 { |
1386 result.push_back(db_->GetPublicId(*it)); | 1364 result.push_back(db_.GetPublicId(*it)); |
1387 } | 1365 } |
1388 } | 1366 } |
1389 | 1367 |
1390 | 1368 |
1391 void ServerIndex::GetChildInstances(std::list<std::string>& result, | 1369 void ServerIndex::GetChildInstances(std::list<std::string>& result, |
1395 | 1373 |
1396 boost::mutex::scoped_lock lock(mutex_); | 1374 boost::mutex::scoped_lock lock(mutex_); |
1397 | 1375 |
1398 ResourceType type; | 1376 ResourceType type; |
1399 int64_t top; | 1377 int64_t top; |
1400 if (!db_->LookupResource(publicId, top, type)) | 1378 if (!db_.LookupResource(publicId, top, type)) |
1401 { | 1379 { |
1402 throw OrthancException(ErrorCode_UnknownResource); | 1380 throw OrthancException(ErrorCode_UnknownResource); |
1403 } | 1381 } |
1404 | 1382 |
1405 if (type == ResourceType_Instance) | 1383 if (type == ResourceType_Instance) |
1418 { | 1396 { |
1419 // Get the internal ID of the current resource | 1397 // Get the internal ID of the current resource |
1420 int64_t resource = toExplore.top(); | 1398 int64_t resource = toExplore.top(); |
1421 toExplore.pop(); | 1399 toExplore.pop(); |
1422 | 1400 |
1423 if (db_->GetResourceType(resource) == ResourceType_Instance) | 1401 if (db_.GetResourceType(resource) == ResourceType_Instance) |
1424 { | 1402 { |
1425 result.push_back(db_->GetPublicId(resource)); | 1403 result.push_back(db_.GetPublicId(resource)); |
1426 } | 1404 } |
1427 else | 1405 else |
1428 { | 1406 { |
1429 // Tag all the children of this resource as to be explored | 1407 // Tag all the children of this resource as to be explored |
1430 db_->GetChildrenInternalId(tmp, resource); | 1408 db_.GetChildrenInternalId(tmp, resource); |
1431 for (std::list<int64_t>::const_iterator | 1409 for (std::list<int64_t>::const_iterator |
1432 it = tmp.begin(); it != tmp.end(); ++it) | 1410 it = tmp.begin(); it != tmp.end(); ++it) |
1433 { | 1411 { |
1434 toExplore.push(*it); | 1412 toExplore.push(*it); |
1435 } | 1413 } |
1444 { | 1422 { |
1445 boost::mutex::scoped_lock lock(mutex_); | 1423 boost::mutex::scoped_lock lock(mutex_); |
1446 | 1424 |
1447 ResourceType rtype; | 1425 ResourceType rtype; |
1448 int64_t id; | 1426 int64_t id; |
1449 if (!db_->LookupResource(publicId, id, rtype)) | 1427 if (!db_.LookupResource(publicId, id, rtype)) |
1450 { | 1428 { |
1451 throw OrthancException(ErrorCode_UnknownResource); | 1429 throw OrthancException(ErrorCode_UnknownResource); |
1452 } | 1430 } |
1453 | 1431 |
1454 db_->SetMetadata(id, type, value); | 1432 db_.SetMetadata(id, type, value); |
1455 } | 1433 } |
1456 | 1434 |
1457 | 1435 |
1458 void ServerIndex::DeleteMetadata(const std::string& publicId, | 1436 void ServerIndex::DeleteMetadata(const std::string& publicId, |
1459 MetadataType type) | 1437 MetadataType type) |
1460 { | 1438 { |
1461 boost::mutex::scoped_lock lock(mutex_); | 1439 boost::mutex::scoped_lock lock(mutex_); |
1462 | 1440 |
1463 ResourceType rtype; | 1441 ResourceType rtype; |
1464 int64_t id; | 1442 int64_t id; |
1465 if (!db_->LookupResource(publicId, id, rtype)) | 1443 if (!db_.LookupResource(publicId, id, rtype)) |
1466 { | 1444 { |
1467 throw OrthancException(ErrorCode_UnknownResource); | 1445 throw OrthancException(ErrorCode_UnknownResource); |
1468 } | 1446 } |
1469 | 1447 |
1470 db_->DeleteMetadata(id, type); | 1448 db_.DeleteMetadata(id, type); |
1471 } | 1449 } |
1472 | 1450 |
1473 | 1451 |
1474 bool ServerIndex::LookupMetadata(std::string& target, | 1452 bool ServerIndex::LookupMetadata(std::string& target, |
1475 const std::string& publicId, | 1453 const std::string& publicId, |
1477 { | 1455 { |
1478 boost::mutex::scoped_lock lock(mutex_); | 1456 boost::mutex::scoped_lock lock(mutex_); |
1479 | 1457 |
1480 ResourceType rtype; | 1458 ResourceType rtype; |
1481 int64_t id; | 1459 int64_t id; |
1482 if (!db_->LookupResource(publicId, id, rtype)) | 1460 if (!db_.LookupResource(publicId, id, rtype)) |
1483 { | 1461 { |
1484 throw OrthancException(ErrorCode_UnknownResource); | 1462 throw OrthancException(ErrorCode_UnknownResource); |
1485 } | 1463 } |
1486 | 1464 |
1487 return db_->LookupMetadata(target, id, type); | 1465 return db_.LookupMetadata(target, id, type); |
1488 } | 1466 } |
1489 | 1467 |
1490 | 1468 |
1491 void ServerIndex::ListAvailableMetadata(std::list<MetadataType>& target, | 1469 void ServerIndex::ListAvailableMetadata(std::list<MetadataType>& target, |
1492 const std::string& publicId) | 1470 const std::string& publicId) |
1493 { | 1471 { |
1494 boost::mutex::scoped_lock lock(mutex_); | 1472 boost::mutex::scoped_lock lock(mutex_); |
1495 | 1473 |
1496 ResourceType rtype; | 1474 ResourceType rtype; |
1497 int64_t id; | 1475 int64_t id; |
1498 if (!db_->LookupResource(publicId, id, rtype)) | 1476 if (!db_.LookupResource(publicId, id, rtype)) |
1499 { | 1477 { |
1500 throw OrthancException(ErrorCode_UnknownResource); | 1478 throw OrthancException(ErrorCode_UnknownResource); |
1501 } | 1479 } |
1502 | 1480 |
1503 db_->ListAvailableMetadata(target, id); | 1481 db_.ListAvailableMetadata(target, id); |
1504 } | 1482 } |
1505 | 1483 |
1506 | 1484 |
1507 void ServerIndex::ListAvailableAttachments(std::list<FileContentType>& target, | 1485 void ServerIndex::ListAvailableAttachments(std::list<FileContentType>& target, |
1508 const std::string& publicId, | 1486 const std::string& publicId, |
1510 { | 1488 { |
1511 boost::mutex::scoped_lock lock(mutex_); | 1489 boost::mutex::scoped_lock lock(mutex_); |
1512 | 1490 |
1513 ResourceType type; | 1491 ResourceType type; |
1514 int64_t id; | 1492 int64_t id; |
1515 if (!db_->LookupResource(publicId, id, type) || | 1493 if (!db_.LookupResource(publicId, id, type) || |
1516 expectedType != type) | 1494 expectedType != type) |
1517 { | 1495 { |
1518 throw OrthancException(ErrorCode_UnknownResource); | 1496 throw OrthancException(ErrorCode_UnknownResource); |
1519 } | 1497 } |
1520 | 1498 |
1521 db_->ListAvailableAttachments(target, id); | 1499 db_.ListAvailableAttachments(target, id); |
1522 } | 1500 } |
1523 | 1501 |
1524 | 1502 |
1525 bool ServerIndex::LookupParent(std::string& target, | 1503 bool ServerIndex::LookupParent(std::string& target, |
1526 const std::string& publicId) | 1504 const std::string& publicId) |
1527 { | 1505 { |
1528 boost::mutex::scoped_lock lock(mutex_); | 1506 boost::mutex::scoped_lock lock(mutex_); |
1529 | 1507 |
1530 ResourceType type; | 1508 ResourceType type; |
1531 int64_t id; | 1509 int64_t id; |
1532 if (!db_->LookupResource(publicId, id, type)) | 1510 if (!db_.LookupResource(publicId, id, type)) |
1533 { | 1511 { |
1534 throw OrthancException(ErrorCode_UnknownResource); | 1512 throw OrthancException(ErrorCode_UnknownResource); |
1535 } | 1513 } |
1536 | 1514 |
1537 int64_t parentId; | 1515 int64_t parentId; |
1538 if (db_->LookupParent(parentId, id)) | 1516 if (db_.LookupParent(parentId, id)) |
1539 { | 1517 { |
1540 target = db_->GetPublicId(parentId); | 1518 target = db_.GetPublicId(parentId); |
1541 return true; | 1519 return true; |
1542 } | 1520 } |
1543 else | 1521 else |
1544 { | 1522 { |
1545 return false; | 1523 return false; |
1549 | 1527 |
1550 uint64_t ServerIndex::IncrementGlobalSequence(GlobalProperty sequence) | 1528 uint64_t ServerIndex::IncrementGlobalSequence(GlobalProperty sequence) |
1551 { | 1529 { |
1552 boost::mutex::scoped_lock lock(mutex_); | 1530 boost::mutex::scoped_lock lock(mutex_); |
1553 | 1531 |
1554 std::auto_ptr<SQLite::ITransaction> transaction(db_->StartTransaction()); | 1532 std::auto_ptr<SQLite::ITransaction> transaction(db_.StartTransaction()); |
1555 | 1533 |
1556 transaction->Begin(); | 1534 transaction->Begin(); |
1557 uint64_t seq = IncrementGlobalSequenceInternal(sequence); | 1535 uint64_t seq = IncrementGlobalSequenceInternal(sequence); |
1558 transaction->Commit(); | 1536 transaction->Commit(); |
1559 | 1537 |
1564 | 1542 |
1565 void ServerIndex::LogChange(ChangeType changeType, | 1543 void ServerIndex::LogChange(ChangeType changeType, |
1566 const std::string& publicId) | 1544 const std::string& publicId) |
1567 { | 1545 { |
1568 boost::mutex::scoped_lock lock(mutex_); | 1546 boost::mutex::scoped_lock lock(mutex_); |
1569 std::auto_ptr<SQLite::ITransaction> transaction(db_->StartTransaction()); | 1547 std::auto_ptr<SQLite::ITransaction> transaction(db_.StartTransaction()); |
1570 transaction->Begin(); | 1548 transaction->Begin(); |
1571 | 1549 |
1572 int64_t id; | 1550 int64_t id; |
1573 ResourceType type; | 1551 ResourceType type; |
1574 if (!db_->LookupResource(publicId, id, type)) | 1552 if (!db_.LookupResource(publicId, id, type)) |
1575 { | 1553 { |
1576 throw OrthancException(ErrorCode_UnknownResource); | 1554 throw OrthancException(ErrorCode_UnknownResource); |
1577 } | 1555 } |
1578 | 1556 |
1579 LogChange(id, changeType, type, publicId); | 1557 LogChange(id, changeType, type, publicId); |
1583 | 1561 |
1584 | 1562 |
1585 void ServerIndex::DeleteChanges() | 1563 void ServerIndex::DeleteChanges() |
1586 { | 1564 { |
1587 boost::mutex::scoped_lock lock(mutex_); | 1565 boost::mutex::scoped_lock lock(mutex_); |
1588 db_->ClearTable("Changes"); | 1566 db_.ClearTable("Changes"); |
1589 } | 1567 } |
1590 | 1568 |
1591 void ServerIndex::DeleteExportedResources() | 1569 void ServerIndex::DeleteExportedResources() |
1592 { | 1570 { |
1593 boost::mutex::scoped_lock lock(mutex_); | 1571 boost::mutex::scoped_lock lock(mutex_); |
1594 db_->ClearTable("ExportedResources"); | 1572 db_.ClearTable("ExportedResources"); |
1595 } | 1573 } |
1596 | 1574 |
1597 | 1575 |
1598 void ServerIndex::GetStatisticsInternal(/* out */ uint64_t& compressedSize, | 1576 void ServerIndex::GetStatisticsInternal(/* out */ uint64_t& compressedSize, |
1599 /* out */ uint64_t& uncompressedSize, | 1577 /* out */ uint64_t& uncompressedSize, |
1616 { | 1594 { |
1617 // Get the internal ID of the current resource | 1595 // Get the internal ID of the current resource |
1618 int64_t resource = toExplore.top(); | 1596 int64_t resource = toExplore.top(); |
1619 toExplore.pop(); | 1597 toExplore.pop(); |
1620 | 1598 |
1621 ResourceType thisType = db_->GetResourceType(resource); | 1599 ResourceType thisType = db_.GetResourceType(resource); |
1622 | 1600 |
1623 std::list<FileContentType> f; | 1601 std::list<FileContentType> f; |
1624 db_->ListAvailableAttachments(f, resource); | 1602 db_.ListAvailableAttachments(f, resource); |
1625 | 1603 |
1626 for (std::list<FileContentType>::const_iterator | 1604 for (std::list<FileContentType>::const_iterator |
1627 it = f.begin(); it != f.end(); ++it) | 1605 it = f.begin(); it != f.end(); ++it) |
1628 { | 1606 { |
1629 FileInfo attachment; | 1607 FileInfo attachment; |
1630 if (db_->LookupAttachment(attachment, resource, *it)) | 1608 if (db_.LookupAttachment(attachment, resource, *it)) |
1631 { | 1609 { |
1632 compressedSize += attachment.GetCompressedSize(); | 1610 compressedSize += attachment.GetCompressedSize(); |
1633 uncompressedSize += attachment.GetUncompressedSize(); | 1611 uncompressedSize += attachment.GetUncompressedSize(); |
1634 } | 1612 } |
1635 } | 1613 } |
1654 break; | 1632 break; |
1655 } | 1633 } |
1656 | 1634 |
1657 // Tag all the children of this resource as to be explored | 1635 // Tag all the children of this resource as to be explored |
1658 std::list<int64_t> tmp; | 1636 std::list<int64_t> tmp; |
1659 db_->GetChildrenInternalId(tmp, resource); | 1637 db_.GetChildrenInternalId(tmp, resource); |
1660 for (std::list<int64_t>::const_iterator | 1638 for (std::list<int64_t>::const_iterator |
1661 it = tmp.begin(); it != tmp.end(); ++it) | 1639 it = tmp.begin(); it != tmp.end(); ++it) |
1662 { | 1640 { |
1663 toExplore.push(*it); | 1641 toExplore.push(*it); |
1664 } | 1642 } |
1683 { | 1661 { |
1684 boost::mutex::scoped_lock lock(mutex_); | 1662 boost::mutex::scoped_lock lock(mutex_); |
1685 | 1663 |
1686 ResourceType type; | 1664 ResourceType type; |
1687 int64_t top; | 1665 int64_t top; |
1688 if (!db_->LookupResource(publicId, top, type)) | 1666 if (!db_.LookupResource(publicId, top, type)) |
1689 { | 1667 { |
1690 throw OrthancException(ErrorCode_UnknownResource); | 1668 throw OrthancException(ErrorCode_UnknownResource); |
1691 } | 1669 } |
1692 | 1670 |
1693 uint64_t uncompressedSize; | 1671 uint64_t uncompressedSize; |
1732 { | 1710 { |
1733 boost::mutex::scoped_lock lock(mutex_); | 1711 boost::mutex::scoped_lock lock(mutex_); |
1734 | 1712 |
1735 ResourceType type; | 1713 ResourceType type; |
1736 int64_t top; | 1714 int64_t top; |
1737 if (!db_->LookupResource(publicId, top, type)) | 1715 if (!db_.LookupResource(publicId, top, type)) |
1738 { | 1716 { |
1739 throw OrthancException(ErrorCode_UnknownResource); | 1717 throw OrthancException(ErrorCode_UnknownResource); |
1740 } | 1718 } |
1741 | 1719 |
1742 GetStatisticsInternal(compressedSize, uncompressedSize, countStudies, | 1720 GetStatisticsInternal(compressedSize, uncompressedSize, countStudies, |
1769 | 1747 |
1770 UnstableResourcePayload payload; | 1748 UnstableResourcePayload payload; |
1771 int64_t id = that->unstableResources_.RemoveOldest(payload); | 1749 int64_t id = that->unstableResources_.RemoveOldest(payload); |
1772 | 1750 |
1773 // Ensure that the resource is still existing before logging the change | 1751 // Ensure that the resource is still existing before logging the change |
1774 if (that->db_->IsExistingResource(id)) | 1752 if (that->db_.IsExistingResource(id)) |
1775 { | 1753 { |
1776 switch (payload.GetResourceType()) | 1754 switch (payload.GetResourceType()) |
1777 { | 1755 { |
1778 case ResourceType_Patient: | 1756 case ResourceType_Patient: |
1779 that->LogChange(id, ChangeType_StablePatient, ResourceType_Patient, payload.GetPublicId()); | 1757 that->LogChange(id, ChangeType_StablePatient, ResourceType_Patient, payload.GetPublicId()); |
1827 result.clear(); | 1805 result.clear(); |
1828 | 1806 |
1829 boost::mutex::scoped_lock lock(mutex_); | 1807 boost::mutex::scoped_lock lock(mutex_); |
1830 | 1808 |
1831 std::list<int64_t> id; | 1809 std::list<int64_t> id; |
1832 db_->LookupIdentifier(id, tag, value); | 1810 db_.LookupIdentifier(id, tag, value); |
1833 | 1811 |
1834 for (std::list<int64_t>::const_iterator | 1812 for (std::list<int64_t>::const_iterator |
1835 it = id.begin(); it != id.end(); ++it) | 1813 it = id.begin(); it != id.end(); ++it) |
1836 { | 1814 { |
1837 if (db_->GetResourceType(*it) == type) | 1815 if (db_.GetResourceType(*it) == type) |
1838 { | 1816 { |
1839 result.push_back(db_->GetPublicId(*it)); | 1817 result.push_back(db_.GetPublicId(*it)); |
1840 } | 1818 } |
1841 } | 1819 } |
1842 } | 1820 } |
1843 | 1821 |
1844 | 1822 |
1849 result.clear(); | 1827 result.clear(); |
1850 | 1828 |
1851 boost::mutex::scoped_lock lock(mutex_); | 1829 boost::mutex::scoped_lock lock(mutex_); |
1852 | 1830 |
1853 std::list<int64_t> id; | 1831 std::list<int64_t> id; |
1854 db_->LookupIdentifier(id, tag, value); | 1832 db_.LookupIdentifier(id, tag, value); |
1855 | 1833 |
1856 for (std::list<int64_t>::const_iterator | 1834 for (std::list<int64_t>::const_iterator |
1857 it = id.begin(); it != id.end(); ++it) | 1835 it = id.begin(); it != id.end(); ++it) |
1858 { | 1836 { |
1859 result.push_back(db_->GetPublicId(*it)); | 1837 result.push_back(db_.GetPublicId(*it)); |
1860 } | 1838 } |
1861 } | 1839 } |
1862 | 1840 |
1863 | 1841 |
1864 void ServerIndex::LookupIdentifier(std::list< std::pair<ResourceType, std::string> >& result, | 1842 void ServerIndex::LookupIdentifier(std::list< std::pair<ResourceType, std::string> >& result, |
1867 result.clear(); | 1845 result.clear(); |
1868 | 1846 |
1869 boost::mutex::scoped_lock lock(mutex_); | 1847 boost::mutex::scoped_lock lock(mutex_); |
1870 | 1848 |
1871 std::list<int64_t> id; | 1849 std::list<int64_t> id; |
1872 db_->LookupIdentifier(id, value); | 1850 db_.LookupIdentifier(id, value); |
1873 | 1851 |
1874 for (std::list<int64_t>::const_iterator | 1852 for (std::list<int64_t>::const_iterator |
1875 it = id.begin(); it != id.end(); ++it) | 1853 it = id.begin(); it != id.end(); ++it) |
1876 { | 1854 { |
1877 result.push_back(std::make_pair(db_->GetResourceType(*it), | 1855 result.push_back(std::make_pair(db_.GetResourceType(*it), |
1878 db_->GetPublicId(*it))); | 1856 db_.GetPublicId(*it))); |
1879 } | 1857 } |
1880 } | 1858 } |
1881 | 1859 |
1882 | 1860 |
1883 StoreStatus ServerIndex::AddAttachment(const FileInfo& attachment, | 1861 StoreStatus ServerIndex::AddAttachment(const FileInfo& attachment, |
1887 | 1865 |
1888 Transaction t(*this); | 1866 Transaction t(*this); |
1889 | 1867 |
1890 ResourceType resourceType; | 1868 ResourceType resourceType; |
1891 int64_t resourceId; | 1869 int64_t resourceId; |
1892 if (!db_->LookupResource(publicId, resourceId, resourceType)) | 1870 if (!db_.LookupResource(publicId, resourceId, resourceType)) |
1893 { | 1871 { |
1894 return StoreStatus_Failure; // Inexistent resource | 1872 return StoreStatus_Failure; // Inexistent resource |
1895 } | 1873 } |
1896 | 1874 |
1897 // Remove possible previous attachment | 1875 // Remove possible previous attachment |
1898 db_->DeleteAttachment(resourceId, attachment.GetContentType()); | 1876 db_.DeleteAttachment(resourceId, attachment.GetContentType()); |
1899 | 1877 |
1900 // Locate the patient of the target resource | 1878 // Locate the patient of the target resource |
1901 int64_t patientId = resourceId; | 1879 int64_t patientId = resourceId; |
1902 for (;;) | 1880 for (;;) |
1903 { | 1881 { |
1904 int64_t parent; | 1882 int64_t parent; |
1905 if (db_->LookupParent(parent, patientId)) | 1883 if (db_.LookupParent(parent, patientId)) |
1906 { | 1884 { |
1907 // We have not reached the patient level yet | 1885 // We have not reached the patient level yet |
1908 patientId = parent; | 1886 patientId = parent; |
1909 } | 1887 } |
1910 else | 1888 else |
1913 break; | 1891 break; |
1914 } | 1892 } |
1915 } | 1893 } |
1916 | 1894 |
1917 // Possibly apply the recycling mechanism while preserving this patient | 1895 // Possibly apply the recycling mechanism while preserving this patient |
1918 assert(db_->GetResourceType(patientId) == ResourceType_Patient); | 1896 assert(db_.GetResourceType(patientId) == ResourceType_Patient); |
1919 Recycle(attachment.GetCompressedSize(), db_->GetPublicId(patientId)); | 1897 Recycle(attachment.GetCompressedSize(), db_.GetPublicId(patientId)); |
1920 | 1898 |
1921 db_->AddAttachment(resourceId, attachment); | 1899 db_.AddAttachment(resourceId, attachment); |
1922 | 1900 |
1923 t.Commit(attachment.GetCompressedSize()); | 1901 t.Commit(attachment.GetCompressedSize()); |
1924 | 1902 |
1925 return StoreStatus_Success; | 1903 return StoreStatus_Success; |
1926 } | 1904 } |
1933 | 1911 |
1934 Transaction t(*this); | 1912 Transaction t(*this); |
1935 | 1913 |
1936 ResourceType rtype; | 1914 ResourceType rtype; |
1937 int64_t id; | 1915 int64_t id; |
1938 if (!db_->LookupResource(publicId, id, rtype)) | 1916 if (!db_.LookupResource(publicId, id, rtype)) |
1939 { | 1917 { |
1940 throw OrthancException(ErrorCode_UnknownResource); | 1918 throw OrthancException(ErrorCode_UnknownResource); |
1941 } | 1919 } |
1942 | 1920 |
1943 db_->DeleteAttachment(id, type); | 1921 db_.DeleteAttachment(id, type); |
1944 | 1922 |
1945 t.Commit(0); | 1923 t.Commit(0); |
1946 } | 1924 } |
1947 | 1925 |
1948 | 1926 |
1953 | 1931 |
1954 target = Json::objectValue; | 1932 target = Json::objectValue; |
1955 | 1933 |
1956 ResourceType type; | 1934 ResourceType type; |
1957 int64_t id; | 1935 int64_t id; |
1958 if (!db_->LookupResource(publicId, id, type)) | 1936 if (!db_.LookupResource(publicId, id, type)) |
1959 { | 1937 { |
1960 return false; | 1938 return false; |
1961 } | 1939 } |
1962 | 1940 |
1963 std::list<MetadataType> metadata; | 1941 std::list<MetadataType> metadata; |
1964 db_->ListAvailableMetadata(metadata, id); | 1942 db_.ListAvailableMetadata(metadata, id); |
1965 | 1943 |
1966 for (std::list<MetadataType>::const_iterator | 1944 for (std::list<MetadataType>::const_iterator |
1967 it = metadata.begin(); it != metadata.end(); it++) | 1945 it = metadata.begin(); it != metadata.end(); it++) |
1968 { | 1946 { |
1969 std::string key = EnumerationToString(*it); | 1947 std::string key = EnumerationToString(*it); |
1970 | 1948 |
1971 std::string value; | 1949 std::string value; |
1972 if (!db_->LookupMetadata(value, id, *it)) | 1950 if (!db_.LookupMetadata(value, id, *it)) |
1973 { | 1951 { |
1974 value.clear(); | 1952 value.clear(); |
1975 } | 1953 } |
1976 | 1954 |
1977 target[key] = value; | 1955 target[key] = value; |
1985 const std::string& defaultValue) | 1963 const std::string& defaultValue) |
1986 { | 1964 { |
1987 boost::mutex::scoped_lock lock(mutex_); | 1965 boost::mutex::scoped_lock lock(mutex_); |
1988 | 1966 |
1989 std::string value; | 1967 std::string value; |
1990 if (db_->LookupGlobalProperty(value, property)) | 1968 if (db_.LookupGlobalProperty(value, property)) |
1991 { | 1969 { |
1992 return value; | 1970 return value; |
1993 } | 1971 } |
1994 else | 1972 else |
1995 { | 1973 { |