changeset 187:8e673a65564d

refactoring of storing new instances
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 12 Nov 2012 17:29:11 +0100
parents f68c039b0571
children 090cefdab1d1
files Core/Toolbox.cpp Core/Toolbox.h OrthancServer/DatabaseWrapper.cpp OrthancServer/DatabaseWrapper.h OrthancServer/OrthancRestApi.cpp OrthancServer/ServerIndex.cpp OrthancServer/ServerIndex.h OrthancServer/main.cpp
diffstat 8 files changed, 167 insertions(+), 42 deletions(-) [+]
line wrap: on
line diff
--- 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 <string.h>
 #include <boost/filesystem.hpp>
 #include <boost/filesystem/fstream.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
 #include <algorithm>
 #include <ctype.h>
 
@@ -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);
+  }
+
 
 }
--- 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();
   }
 }
--- 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, 
--- 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_);
+    }
   };
 }
--- 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<const char*>(&postData[0]),
+          (storage_, reinterpret_cast<const char*>(&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<std::string>(index_.GetTotalCompressedSize());
+        result["TotalUncompressedSize"] = boost::lexical_cast<std::string>(index_.GetTotalUncompressedSize());
         existingResource = true;
       }
       else
--- 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<SQLite::Transaction> 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)
   {
--- 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);
 
--- 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<const char*>(&dicomFile[0]), dicomFile.size(),
                    dicomSummary, dicomJson, remoteAet);
     }