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 {