changeset 1161:82cbf1480aac db-changes

mainline->db-changes integration
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 17 Sep 2014 12:38:28 +0200
parents 8f9d49192815 (diff) 80671157d051 (current diff)
children 1ea4094d077c
files
diffstat 7 files changed, 162 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Wed Sep 17 11:57:28 2014 +0200
+++ b/CMakeLists.txt	Wed Sep 17 12:38:28 2014 +0200
@@ -264,6 +264,7 @@
 set(EMBEDDED_FILES
   PREPARE_DATABASE ${CMAKE_CURRENT_SOURCE_DIR}/OrthancServer/PrepareDatabase.sql
   UPGRADE_DATABASE_3_TO_4 ${CMAKE_CURRENT_SOURCE_DIR}/OrthancServer/Upgrade3To4.sql
+  UPGRADE_DATABASE_4_TO_5 ${CMAKE_CURRENT_SOURCE_DIR}/OrthancServer/Upgrade4To5.sql
   CONFIGURATION_SAMPLE ${CMAKE_CURRENT_SOURCE_DIR}/Resources/Configuration.json
   DICOM_CONFORMANCE_STATEMENT ${CMAKE_CURRENT_SOURCE_DIR}/Resources/DicomConformanceStatement.txt
   LUA_TOOLBOX ${CMAKE_CURRENT_SOURCE_DIR}/Resources/Toolbox.lua
--- a/OrthancServer/DatabaseWrapper.cpp	Wed Sep 17 11:57:28 2014 +0200
+++ b/OrthancServer/DatabaseWrapper.cpp	Wed Sep 17 12:38:28 2014 +0200
@@ -92,6 +92,34 @@
       }
     };
 
+    class SignalResourceDeleted : public SQLite::IScalarFunction
+    {
+    private:
+      IServerIndexListener& listener_;
+
+    public:
+      SignalResourceDeleted(IServerIndexListener& listener) :
+        listener_(listener)
+      {
+      }
+
+      virtual const char* GetName() const
+      {
+        return "SignalResourceDeleted";
+      }
+
+      virtual unsigned int GetCardinality() const
+      {
+        return 2;
+      }
+
+      virtual void Compute(SQLite::FunctionContext& context)
+      {
+        ResourceType type = static_cast<ResourceType>(context.GetIntValue(1));
+        listener_.SignalResourceDeleted(type, context.GetStringValue(0));
+      }
+    };
+
     class SignalRemainingAncestor : public SQLite::IScalarFunction
     {
     private:
@@ -852,11 +880,12 @@
       /**
        * History of the database versions:
        *  - Version 3: from Orthanc 0.3.2 to Orthanc 0.7.2 (inclusive)
-       *  - Version 4: from Orthanc 0.7.3 (inclusive)
+       *  - Version 4: from Orthanc 0.7.3 to Orthanc 0.8.3 (inclusive)
+       *  - Version 5: from Orthanc 0.8.4 (inclusive)
        **/
 
-      // This version of Orthanc is only compatible with versions 3 of 4 of the DB schema
-      ok = (v == 3 || v == 4);
+      // This version of Orthanc is only compatible with versions 3, 4 and 5 of the DB schema
+      ok = (v == 3 || v == 4 || v == 5);
 
       if (v == 3)
       {
@@ -866,6 +895,18 @@
         db_.BeginTransaction();
         db_.Execute(upgrade);
         db_.CommitTransaction();
+        v = 4;
+      }
+
+      if (v == 4)
+      {
+        LOG(WARNING) << "Upgrading database version from 4 to 5";
+        std::string upgrade;
+        EmbeddedResources::GetFileResource(upgrade, EmbeddedResources::UPGRADE_DATABASE_4_TO_5);
+        db_.BeginTransaction();
+        db_.Execute(upgrade);
+        db_.CommitTransaction();
+        v = 5;
       }
     }
     catch (boost::bad_lexical_cast&)
@@ -881,6 +922,7 @@
     signalRemainingAncestor_ = new Internals::SignalRemainingAncestor;
     db_.Register(signalRemainingAncestor_);
     db_.Register(new Internals::SignalFileDeleted(listener_));
+    db_.Register(new Internals::SignalResourceDeleted(listener_));
   }
 
   uint64_t DatabaseWrapper::GetResourceCount(ResourceType resourceType)
--- a/OrthancServer/IServerIndexListener.h	Wed Sep 17 11:57:28 2014 +0200
+++ b/OrthancServer/IServerIndexListener.h	Wed Sep 17 12:38:28 2014 +0200
@@ -47,6 +47,9 @@
     virtual void SignalRemainingAncestor(ResourceType parentType,
                                          const std::string& publicId) = 0;
 
+    virtual void SignalResourceDeleted(ResourceType type,
+                                       const std::string& publicId) = 0;
+
     virtual void SignalFileDeleted(const FileInfo& info) = 0;
   };
 }
--- a/OrthancServer/PrepareDatabase.sql	Wed Sep 17 11:57:28 2014 +0200
+++ b/OrthancServer/PrepareDatabase.sql	Wed Sep 17 12:38:28 2014 +0200
@@ -18,6 +18,15 @@
        PRIMARY KEY(id, tagGroup, tagElement)
        );
 
+-- The following table was added in Orthanc 0.8.4 (database v5)
+CREATE TABLE DicomIdentifiers(
+       id INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE,
+       tagGroup INTEGER,
+       tagElement INTEGER,
+       value TEXT,
+       PRIMARY KEY(id, tagGroup, tagElement)
+       );
+
 CREATE TABLE Metadata(
        id INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE,
        type INTEGER,
@@ -68,8 +77,14 @@
 CREATE INDEX PatientRecyclingIndex ON PatientRecyclingOrder(patientId);
 
 CREATE INDEX MainDicomTagsIndex1 ON MainDicomTags(id);
-CREATE INDEX MainDicomTagsIndex2 ON MainDicomTags(tagGroup, tagElement);
-CREATE INDEX MainDicomTagsIndexValues ON MainDicomTags(value COLLATE BINARY);
+-- The 2 following indexes were removed in Orthanc 0.8.4 (database v5), to speed up
+-- CREATE INDEX MainDicomTagsIndex2 ON MainDicomTags(tagGroup, tagElement);
+-- CREATE INDEX MainDicomTagsIndexValues ON MainDicomTags(value COLLATE BINARY);
+
+-- The 3 following indexes were added in Orthanc 0.8.4 (database v5)
+CREATE INDEX DicomIdentifiersIndex1 ON DicomIdentifiers(id);
+CREATE INDEX DicomIdentifiersIndex2 ON DicomIdentifiers(tagGroup, tagElement);
+CREATE INDEX DicomIdentifiersIndexValues ON DicomIdentifiers(value COLLATE BINARY);
 
 CREATE INDEX ChangesIndex ON Changes(internalId);
 
@@ -85,6 +100,7 @@
 CREATE TRIGGER ResourceDeleted
 AFTER DELETE ON Resources
 BEGIN
+  SELECT SignalResourceDeleted(old.publicId, old.resourceType);  -- New in Orthanc 0.8.4 (db v5)
   SELECT SignalRemainingAncestor(parent.publicId, parent.resourceType) 
     FROM Resources AS parent WHERE internalId = old.parentId;
 END;
@@ -107,4 +123,4 @@
 
 -- Set the version of the database schema
 -- The "1" corresponds to the "GlobalProperty_DatabaseSchemaVersion" enumeration
-INSERT INTO GlobalProperties VALUES (1, "4");
+INSERT INTO GlobalProperties VALUES (1, "5");
--- a/OrthancServer/ServerIndex.cpp	Wed Sep 17 11:57:28 2014 +0200
+++ b/OrthancServer/ServerIndex.cpp	Wed Sep 17 12:38:28 2014 +0200
@@ -137,6 +137,13 @@
         sizeOfFilesToRemove_ += info.GetCompressedSize();
       }
 
+      virtual void SignalResourceDeleted(ResourceType type,
+                                         const std::string& publicId)
+      {
+        LOG(INFO) << "Resource " << publicId << " of type " << EnumerationToString(type) << " is deleted";
+      }
+
+
       bool HasRemainingLevel() const
       {
         return hasRemainingLevel_;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OrthancServer/Upgrade4To5.sql	Wed Sep 17 12:38:28 2014 +0200
@@ -0,0 +1,58 @@
+-- This SQLite script updates the version of the Orthanc database from 4 to 5.
+
+
+-- Remove 2 indexes to speed up
+
+DROP INDEX MainDicomTagsIndex2;
+DROP INDEX MainDicomTagsIndexValues;
+
+
+-- Add a new table to index the DICOM identifiers
+
+CREATE TABLE DicomIdentifiers(
+       id INTEGER REFERENCES Resources(internalId) ON DELETE CASCADE,
+       tagGroup INTEGER,
+       tagElement INTEGER,
+       value TEXT,
+       PRIMARY KEY(id, tagGroup, tagElement)
+       );
+
+CREATE INDEX DicomIdentifiersIndex1 ON DicomIdentifiers(id);
+CREATE INDEX DicomIdentifiersIndex2 ON DicomIdentifiers(tagGroup, tagElement);
+CREATE INDEX DicomIdentifiersIndexValues ON DicomIdentifiers(value COLLATE BINARY);
+
+
+-- Migrate data from MainDicomTags to MainResourcesTags and MainInstancesTags
+
+INSERT INTO DicomIdentifiers SELECT * FROM MainDicomTags
+       WHERE ((tagGroup = 16 AND tagElement = 32) OR  -- PatientID (0x0010, 0x0020)
+              (tagGroup = 32 AND tagElement = 13) OR  -- StudyInstanceUID (0x0020, 0x000d)
+              (tagGroup = 8  AND tagElement = 80) OR  -- AccessionNumber (0x0008, 0x0050)
+              (tagGroup = 32 AND tagElement = 14) OR  -- SeriesInstanceUID (0x0020, 0x000e)
+              (tagGroup = 8  AND tagElement = 24));   -- SOPInstanceUID (0x0008, 0x0018)
+
+DELETE FROM MainDicomTags
+       WHERE ((tagGroup = 16 AND tagElement = 32) OR  -- PatientID (0x0010, 0x0020)
+              (tagGroup = 32 AND tagElement = 13) OR  -- StudyInstanceUID (0x0020, 0x000d)
+              (tagGroup = 8  AND tagElement = 80) OR  -- AccessionNumber (0x0008, 0x0050)
+              (tagGroup = 32 AND tagElement = 14) OR  -- SeriesInstanceUID (0x0020, 0x000e)
+              (tagGroup = 8  AND tagElement = 24));   -- SOPInstanceUID (0x0008, 0x0018)
+
+
+-- Upgrade the "ResourceDeleted" trigger
+
+DROP TRIGGER ResourceDeleted;
+
+CREATE TRIGGER ResourceDeleted
+AFTER DELETE ON Resources
+BEGIN
+  SELECT SignalResourceDeleted(old.publicId, old.resourceType);
+  SELECT SignalRemainingAncestor(parent.publicId, parent.resourceType) 
+    FROM Resources AS parent WHERE internalId = old.parentId;
+END;
+
+
+-- Change the database version
+-- The "1" corresponds to the "GlobalProperty_DatabaseSchemaVersion" enumeration
+
+UPDATE GlobalProperties SET value="5" WHERE property=1;
--- a/UnitTestsSources/ServerIndexTests.cpp	Wed Sep 17 11:57:28 2014 +0200
+++ b/UnitTestsSources/ServerIndexTests.cpp	Wed Sep 17 12:38:28 2014 +0200
@@ -58,6 +58,7 @@
   {
   public:
     std::vector<std::string> deletedFiles_;
+    std::vector<std::string> deletedResources_;
     std::string ancestorId_;
     ResourceType ancestorType_;
 
@@ -79,7 +80,15 @@
       const std::string fileUuid = info.GetUuid();
       deletedFiles_.push_back(fileUuid);
       LOG(INFO) << "A file must be removed: " << fileUuid;
-    }                                
+    }       
+
+    virtual void SignalResourceDeleted(ResourceType type,
+                                       const std::string& publicId)
+    {
+      deletedResources_.push_back(publicId);
+      LOG(INFO) << "A resource was removed: " << publicId;
+    }
+                         
   };
 
 
@@ -281,12 +290,14 @@
   ASSERT_EQ(CompressionType_None, att.GetCompressionType());
 
   ASSERT_EQ(0u, listener_->deletedFiles_.size());
+  ASSERT_EQ(0u, listener_->deletedResources_.size());
   ASSERT_EQ(7u, index_->GetTableRecordCount("Resources")); 
   ASSERT_EQ(3u, index_->GetTableRecordCount("AttachedFiles"));
   ASSERT_EQ(1u, index_->GetTableRecordCount("Metadata"));
   ASSERT_EQ(1u, index_->GetTableRecordCount("MainDicomTags"));
+
   index_->DeleteResource(a[0]);
-
+  ASSERT_EQ(5u, listener_->deletedResources_.size());
   ASSERT_EQ(2u, listener_->deletedFiles_.size());
   ASSERT_FALSE(std::find(listener_->deletedFiles_.begin(), 
                          listener_->deletedFiles_.end(),
@@ -300,6 +311,7 @@
   ASSERT_EQ(1u, index_->GetTableRecordCount("AttachedFiles"));
   ASSERT_EQ(0u, index_->GetTableRecordCount("MainDicomTags"));
   index_->DeleteResource(a[5]);
+  ASSERT_EQ(7u, listener_->deletedResources_.size());
   ASSERT_EQ(0u, index_->GetTableRecordCount("Resources"));
   ASSERT_EQ(0u, index_->GetTableRecordCount("AttachedFiles"));
   ASSERT_EQ(2u, index_->GetTableRecordCount("GlobalProperties"));
@@ -395,9 +407,11 @@
   ASSERT_EQ(10u, index_->GetTableRecordCount("PatientRecyclingOrder")); 
 
   listener_->Reset();
+  ASSERT_EQ(0u, listener_->deletedResources_.size());
 
   index_->DeleteResource(patients[5]);
   index_->DeleteResource(patients[0]);
+  ASSERT_EQ(2u, listener_->deletedResources_.size());
   ASSERT_EQ(8u, index_->GetTableRecordCount("Resources")); 
   ASSERT_EQ(8u, index_->GetTableRecordCount("PatientRecyclingOrder"));
 
@@ -408,20 +422,27 @@
   int64_t p;
   ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[1]);
   index_->DeleteResource(p);
+  ASSERT_EQ(3u, listener_->deletedResources_.size());
   ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[2]);
   index_->DeleteResource(p);
+  ASSERT_EQ(4u, listener_->deletedResources_.size());
   ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[3]);
   index_->DeleteResource(p);
+  ASSERT_EQ(5u, listener_->deletedResources_.size());
   ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[4]);
   index_->DeleteResource(p);
+  ASSERT_EQ(6u, listener_->deletedResources_.size());
   ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[6]);
   index_->DeleteResource(p);
   index_->DeleteResource(patients[8]);
+  ASSERT_EQ(8u, listener_->deletedResources_.size());
   ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[7]);
   index_->DeleteResource(p);
+  ASSERT_EQ(9u, listener_->deletedResources_.size());
   ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[9]);
   index_->DeleteResource(p);
   ASSERT_FALSE(index_->SelectPatientToRecycle(p));
+  ASSERT_EQ(10u, listener_->deletedResources_.size());
 
   ASSERT_EQ(10u, listener_->deletedFiles_.size());
   ASSERT_EQ(0u, index_->GetTableRecordCount("Resources")); 
@@ -477,16 +498,21 @@
 
   // Unprotecting a patient puts it at the last position in the recycling queue
   int64_t p;
+  ASSERT_EQ(0u, listener_->deletedResources_.size());
   ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[0]);
   index_->DeleteResource(p);
+  ASSERT_EQ(1u, listener_->deletedResources_.size());
   ASSERT_TRUE(index_->SelectPatientToRecycle(p, patients[1])); ASSERT_EQ(p, patients[4]);
   ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[1]);
   index_->DeleteResource(p);
+  ASSERT_EQ(2u, listener_->deletedResources_.size());
   ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[4]);
   index_->DeleteResource(p);
+  ASSERT_EQ(3u, listener_->deletedResources_.size());
   ASSERT_FALSE(index_->SelectPatientToRecycle(p, patients[2]));
   ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[2]);
   index_->DeleteResource(p);
+  ASSERT_EQ(4u, listener_->deletedResources_.size());
   // "patients[3]" is still protected
   ASSERT_FALSE(index_->SelectPatientToRecycle(p));
 
@@ -500,6 +526,7 @@
   ASSERT_TRUE(index_->SelectPatientToRecycle(p, patients[2]));
   ASSERT_TRUE(index_->SelectPatientToRecycle(p)); ASSERT_EQ(p, patients[3]);
   index_->DeleteResource(p);
+  ASSERT_EQ(5u, listener_->deletedResources_.size());
 
   ASSERT_EQ(5u, listener_->deletedFiles_.size());
   ASSERT_EQ(0u, index_->GetTableRecordCount("Resources"));