# HG changeset patch # User Sebastien Jodogne # Date 1352737751 -3600 # Node ID 8e673a65564dbf1942fd09a6cafdc5430fe02ecc # Parent f68c039b0571b9ed63dc4eed517ac233417a9617 refactoring of storing new instances diff -r f68c039b0571 -r 8e673a65564d Core/Toolbox.cpp --- a/Core/Toolbox.cpp Mon Nov 12 15:29:07 2012 +0100 +++ b/Core/Toolbox.cpp Mon Nov 12 17:29:11 2012 +0100 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -550,5 +551,11 @@ } } + std::string Toolbox::GetNowIsoString() + { + boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); + return boost::posix_time::to_iso_string(now); + } + } diff -r f68c039b0571 -r 8e673a65564d Core/Toolbox.h --- a/Core/Toolbox.h Mon Nov 12 15:29:07 2012 +0100 +++ b/Core/Toolbox.h Mon Nov 12 17:29:11 2012 +0100 @@ -86,5 +86,7 @@ const char* fromEncoding); std::string ConvertToAscii(const std::string& source); + + std::string GetNowIsoString(); } } diff -r f68c039b0571 -r 8e673a65564d OrthancServer/DatabaseWrapper.cpp --- a/OrthancServer/DatabaseWrapper.cpp Mon Nov 12 15:29:07 2012 +0100 +++ b/OrthancServer/DatabaseWrapper.cpp Mon Nov 12 17:29:11 2012 +0100 @@ -278,8 +278,8 @@ void DatabaseWrapper::AttachFile(int64_t id, const std::string& name, const std::string& fileUuid, - size_t compressedSize, - size_t uncompressedSize, + uint64_t compressedSize, + uint64_t uncompressedSize, CompressionType compressionType) { SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO AttachedFiles VALUES(?, ?, ?, ?, ?, ?)"); @@ -295,8 +295,8 @@ bool DatabaseWrapper::FindFile(int64_t id, const std::string& name, std::string& fileUuid, - size_t& compressedSize, - size_t& uncompressedSize, + uint64_t& compressedSize, + uint64_t& uncompressedSize, CompressionType& compressionType) { SQLite::Statement s(db_, SQLITE_FROM_HERE, diff -r f68c039b0571 -r 8e673a65564d OrthancServer/DatabaseWrapper.h --- a/OrthancServer/DatabaseWrapper.h Mon Nov 12 15:29:07 2012 +0100 +++ b/OrthancServer/DatabaseWrapper.h Mon Nov 12 17:29:11 2012 +0100 @@ -33,6 +33,7 @@ #pragma once #include "../Core/SQLite/Connection.h" +#include "../Core/SQLite/Transaction.h" #include "../Core/DicomFormat/DicomInstanceHasher.h" #include "IServerIndexListener.h" @@ -97,14 +98,14 @@ void AttachFile(int64_t id, const std::string& name, const std::string& fileUuid, - size_t compressedSize, - size_t uncompressedSize, + uint64_t compressedSize, + uint64_t uncompressedSize, CompressionType compressionType); void AttachFile(int64_t id, const std::string& name, const std::string& fileUuid, - size_t fileSize) + uint64_t fileSize) { AttachFile(id, name, fileUuid, fileSize, fileSize, CompressionType_None); } @@ -112,8 +113,8 @@ bool FindFile(int64_t id, const std::string& name, std::string& fileUuid, - size_t& compressedSize, - size_t& uncompressedSize, + uint64_t& compressedSize, + uint64_t& uncompressedSize, CompressionType& compressionType); void SetMainDicomTags(int64_t id, @@ -147,5 +148,10 @@ IServerIndexListener& listener); DatabaseWrapper(IServerIndexListener& listener); + + SQLite::Transaction* StartTransaction() + { + return new SQLite::Transaction(db_); + } }; } diff -r f68c039b0571 -r 8e673a65564d OrthancServer/OrthancRestApi.cpp --- a/OrthancServer/OrthancRestApi.cpp Mon Nov 12 15:29:07 2012 +0100 +++ b/OrthancServer/OrthancRestApi.cpp Mon Nov 12 17:29:11 2012 +0100 @@ -133,30 +133,30 @@ { DicomMap dicomSummary; FromDcmtkBridge::Convert(dicomSummary, *dicomFile.getDataset()); - + + DicomInstanceHasher hasher(dicomSummary); + Json::Value dicomJson; FromDcmtkBridge::ToJson(dicomJson, *dicomFile.getDataset()); - std::string instanceUuid; StoreStatus status = StoreStatus_Failure; if (postData.size() > 0) { status = index_.Store - (instanceUuid, storage_, reinterpret_cast(&postData[0]), + (storage_, reinterpret_cast(&postData[0]), postData.size(), dicomSummary, dicomJson, ""); } + result["ID"] = hasher.HashInstance(); + result["Path"] = "/instances/" + hasher.HashInstance(); + switch (status) { case StoreStatus_Success: - result["ID"] = instanceUuid; - result["Path"] = "/instances/" + instanceUuid; result["Status"] = "Success"; return true; case StoreStatus_AlreadyStored: - result["ID"] = instanceUuid; - result["Path"] = "/instances/" + instanceUuid; result["Status"] = "AlreadyStored"; return true; @@ -427,6 +427,8 @@ result = Json::Value(Json::objectValue); result["Version"] = ORTHANC_VERSION; result["Name"] = GetGlobalStringParameter("Name", ""); + result["TotalCompressedSize"] = boost::lexical_cast(index_.GetTotalCompressedSize()); + result["TotalUncompressedSize"] = boost::lexical_cast(index_.GetTotalUncompressedSize()); existingResource = true; } else diff -r f68c039b0571 -r 8e673a65564d OrthancServer/ServerIndex.cpp --- a/OrthancServer/ServerIndex.cpp Mon Nov 12 15:29:07 2012 +0100 +++ b/OrthancServer/ServerIndex.cpp Mon Nov 12 17:29:11 2012 +0100 @@ -239,7 +239,7 @@ const std::string& fileUuid, uint64_t fileSize, const std::string& jsonUuid, - const std::string& distantAet) + const std::string& remoteAet) { SQLite::Statement s2(db_, SQLITE_FROM_HERE, "INSERT INTO Resources VALUES(?, ?)"); s2.BindString(0, hasher.HashInstance()); @@ -253,7 +253,7 @@ s.BindString(3, fileUuid); s.BindInt64(4, fileSize); s.BindString(5, jsonUuid); - s.BindString(6, distantAet); + s.BindString(6, remoteAet); const DicomValue* indexInSeries; if ((indexInSeries = dicomSummary.TestAndGetValue(DICOM_TAG_INSTANCE_NUMBER)) != NULL || @@ -511,13 +511,112 @@ } - StoreStatus ServerIndex::Store(std::string& instanceUuid, - const DicomMap& dicomSummary, + StoreStatus ServerIndex::Store2(const DicomMap& dicomSummary, + const std::string& fileUuid, + uint64_t uncompressedFileSize, + const std::string& jsonUuid, + const std::string& remoteAet) + { + boost::mutex::scoped_lock scoped_lock(mutex_); + + DicomInstanceHasher hasher(dicomSummary); + + try + { + std::auto_ptr t(db2_->StartTransaction()); + t->Begin(); + + int64_t patient, study, series, instance; + ResourceType type; + bool isNewSeries = false; + + // Do nothing if the instance already exists + if (db2_->FindResource(hasher.HashInstance(), patient, type)) + { + assert(type == ResourceType_Patient); + return StoreStatus_AlreadyStored; + } + + // Create the patient/study/series/instance hierarchy + instance = db2_->CreateResource(hasher.HashInstance(), ResourceType_Instance); + + if (!db2_->FindResource(hasher.HashSeries(), series, type)) + { + // This is a new series + isNewSeries = true; + series = db2_->CreateResource(hasher.HashSeries(), ResourceType_Series); + db2_->AttachChild(series, instance); + + if (!db2_->FindResource(hasher.HashStudy(), study, type)) + { + // This is a new study + study = db2_->CreateResource(hasher.HashStudy(), ResourceType_Study); + db2_->AttachChild(study, series); + + if (!db2_->FindResource(hasher.HashPatient(), patient, type)) + { + // This is a new patient + patient = db2_->CreateResource(hasher.HashPatient(), ResourceType_Patient); + db2_->AttachChild(patient, study); + } + else + { + assert(type == ResourceType_Patient); + } + } + else + { + assert(type == ResourceType_Study); + } + } + else + { + assert(type == ResourceType_Series); + } + + // Attach the files to the newly created instance + db2_->AttachFile(instance, "_dicom", fileUuid, uncompressedFileSize); + db2_->AttachFile(instance, "_json", jsonUuid, 0); // TODO "0" + + // Attach the metadata + db2_->SetMetadata(instance, MetadataType_Instance_ReceptionDate, Toolbox::GetNowIsoString()); + db2_->SetMetadata(instance, MetadataType_Instance_RemoteAet, remoteAet); + + const DicomValue* value; + if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_INSTANCE_NUMBER)) != NULL || + (value = dicomSummary.TestAndGetValue(DICOM_TAG_IMAGE_INDEX)) != NULL) + { + db2_->SetMetadata(instance, MetadataType_Instance_IndexInSeries, value->AsString()); + } + + if (isNewSeries) + { + if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_NUMBER_OF_SLICES)) != NULL || + (value = dicomSummary.TestAndGetValue(DICOM_TAG_IMAGES_IN_ACQUISITION)) != NULL) + { + db2_->SetMetadata(series, MetadataType_Series_ExpectedNumberOfInstances, value->AsString()); + } + } + + t->Commit(); + } + catch (OrthancException& e) + { + LOG(ERROR) << "EXCEPTION2 [" << e.What() << "]" << " " << db_.GetErrorMessage(); + } + + return StoreStatus_Failure; + } + + + StoreStatus ServerIndex::Store(const DicomMap& dicomSummary, const std::string& fileUuid, uint64_t uncompressedFileSize, const std::string& jsonUuid, - const std::string& distantAet) + const std::string& remoteAet) { + Store2(dicomSummary, fileUuid, uncompressedFileSize, jsonUuid, remoteAet); + boost::mutex::scoped_lock scoped_lock(mutex_); DicomInstanceHasher hasher(dicomSummary); @@ -561,7 +660,7 @@ } CreateInstance(hasher, dicomSummary, fileUuid, - uncompressedFileSize, jsonUuid, distantAet); + uncompressedFileSize, jsonUuid, remoteAet); t.Commit(); return StoreStatus_Success; @@ -576,18 +675,16 @@ } - StoreStatus ServerIndex::Store(std::string& instanceUuid, - FileStorage& storage, + StoreStatus ServerIndex::Store(FileStorage& storage, const char* dicomFile, size_t dicomSize, const DicomMap& dicomSummary, const Json::Value& dicomJson, - const std::string& distantAet) + const std::string& remoteAet) { std::string fileUuid = storage.Create(dicomFile, dicomSize); std::string jsonUuid = storage.Create(dicomJson.toStyledString()); - StoreStatus status = Store(instanceUuid, dicomSummary, fileUuid, - dicomSize, jsonUuid, distantAet); + StoreStatus status = Store(dicomSummary, fileUuid, dicomSize, jsonUuid, remoteAet); if (status != StoreStatus_Success) { @@ -598,7 +695,7 @@ switch (status) { case StoreStatus_Success: - LOG(WARNING) << "New instance stored: " << GetTotalSize() << " bytes"; + LOG(WARNING) << "New instance stored"; break; case StoreStatus_AlreadyStored: @@ -613,14 +710,20 @@ return status; } - uint64_t ServerIndex::GetTotalSize() + uint64_t ServerIndex::GetTotalCompressedSize() { boost::mutex::scoped_lock scoped_lock(mutex_); - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT SUM(fileSize) FROM Instances"); - s.Run(); - return s.ColumnInt64(0); + return db2_->GetTotalCompressedSize(); } + uint64_t ServerIndex::GetTotalUncompressedSize() + { + boost::mutex::scoped_lock scoped_lock(mutex_); + return db2_->GetTotalUncompressedSize(); + } + + + SeriesStatus ServerIndex::GetSeriesStatus(const std::string& seriesUuid) { diff -r f68c039b0571 -r 8e673a65564d OrthancServer/ServerIndex.h --- a/OrthancServer/ServerIndex.h Mon Nov 12 15:29:07 2012 +0100 +++ b/OrthancServer/ServerIndex.h Mon Nov 12 17:29:11 2012 +0100 @@ -96,7 +96,7 @@ const std::string& fileUuid, uint64_t fileSize, const std::string& jsonUuid, - const std::string& distantAet); + const std::string& remoteAet); @@ -115,25 +115,31 @@ const std::string& uuid, const std::string& tableName); + StoreStatus Store2(const DicomMap& dicomSummary, + const std::string& fileUuid, + uint64_t uncompressedFileSize, + const std::string& jsonUuid, + const std::string& remoteAet); + public: ServerIndex(const std::string& storagePath); - StoreStatus Store(std::string& instanceUuid, - const DicomMap& dicomSummary, + StoreStatus Store(const DicomMap& dicomSummary, const std::string& fileUuid, uint64_t uncompressedFileSize, const std::string& jsonUuid, - const std::string& distantAet); + const std::string& remoteAet); - StoreStatus Store(std::string& instanceUuid, - FileStorage& storage, + StoreStatus Store(FileStorage& storage, const char* dicomFile, size_t dicomSize, const DicomMap& dicomSummary, const Json::Value& dicomJson, - const std::string& distantAet); + const std::string& remoteAet); - uint64_t GetTotalSize(); + uint64_t GetTotalCompressedSize(); + + uint64_t GetTotalUncompressedSize(); SeriesStatus GetSeriesStatus(const std::string& seriesUuid); diff -r f68c039b0571 -r 8e673a65564d OrthancServer/main.cpp --- a/OrthancServer/main.cpp Mon Nov 12 15:29:07 2012 +0100 +++ b/OrthancServer/main.cpp Mon Nov 12 17:29:11 2012 +0100 @@ -65,10 +65,9 @@ const Json::Value& dicomJson, const std::string& remoteAet) { - std::string instanceUuid; if (dicomFile.size() > 0) { - index_.Store(instanceUuid, storage_, + index_.Store(storage_, reinterpret_cast(&dicomFile[0]), dicomFile.size(), dicomSummary, dicomJson, remoteAet); }