# HG changeset patch # User Sebastien Jodogne # Date 1410950308 -7200 # Node ID 82cbf1480aacf5fe27316649536803cce1081fbd # Parent 8f9d49192815faa3d70dc709c43393daea16bb35# Parent 80671157d051a83d7b83dfa16f9e9ae9f6c201c0 mainline->db-changes integration diff -r 80671157d051 -r 82cbf1480aac CMakeLists.txt --- 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 diff -r 80671157d051 -r 82cbf1480aac OrthancServer/DatabaseWrapper.cpp --- 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(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) diff -r 80671157d051 -r 82cbf1480aac OrthancServer/IServerIndexListener.h --- 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; }; } diff -r 80671157d051 -r 82cbf1480aac OrthancServer/PrepareDatabase.sql --- 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"); diff -r 80671157d051 -r 82cbf1480aac OrthancServer/ServerIndex.cpp --- 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_; diff -r 80671157d051 -r 82cbf1480aac OrthancServer/Upgrade4To5.sql --- /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; diff -r 80671157d051 -r 82cbf1480aac UnitTestsSources/ServerIndexTests.cpp --- 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 deletedFiles_; + std::vector 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"));