# HG changeset patch # User Sebastien Jodogne # Date 1547139754 -3600 # Node ID 2e1711f80f74753723691db2efb395b7afaa3bdd # Parent b2b6db5ad9a5c5f38906de07d9fb8d67ab09238e More consistent handling of the "Last" field returned by the "/changes" URI diff -r b2b6db5ad9a5 -r 2e1711f80f74 NEWS --- a/NEWS Mon Jan 07 17:23:04 2019 +0100 +++ b/NEWS Thu Jan 10 18:02:34 2019 +0100 @@ -1,6 +1,16 @@ Pending changes in the mainline =============================== +REST API +-------- + +* More consistent handling of the "Last" field returned by the "/changes" URI + +Plugins +------- + +* New primitives to speed up databases (custom index plugins) + Maintenance ----------- diff -r b2b6db5ad9a5 -r 2e1711f80f74 OrthancServer/Database/IDatabaseWrapper.h --- a/OrthancServer/Database/IDatabaseWrapper.h Mon Jan 07 17:23:04 2019 +0100 +++ b/OrthancServer/Database/IDatabaseWrapper.h Thu Jan 10 18:02:34 2019 +0100 @@ -240,5 +240,7 @@ virtual void GetChildrenMetadata(std::list& target, int64_t resourceId, MetadataType metadata) = 0; + + virtual int64_t GetLastChangeIndex() = 0; }; } diff -r b2b6db5ad9a5 -r 2e1711f80f74 OrthancServer/Database/SQLiteDatabaseWrapper.cpp --- a/OrthancServer/Database/SQLiteDatabaseWrapper.cpp Mon Jan 07 17:23:04 2019 +0100 +++ b/OrthancServer/Database/SQLiteDatabaseWrapper.cpp Thu Jan 10 18:02:34 2019 +0100 @@ -1270,4 +1270,23 @@ } } } + + + int64_t SQLiteDatabaseWrapper::GetLastChangeIndex() + { + SQLite::Statement s(db_, SQLITE_FROM_HERE, + "SELECT seq FROM sqlite_sequence WHERE name='Changes'"); + + if (s.Step()) + { + int64_t c = s.ColumnInt(0); + assert(!s.Step()); + return c; + } + else + { + // No change has been recorded so far in the database + return 0; + } + } } diff -r b2b6db5ad9a5 -r 2e1711f80f74 OrthancServer/Database/SQLiteDatabaseWrapper.h --- a/OrthancServer/Database/SQLiteDatabaseWrapper.h Mon Jan 07 17:23:04 2019 +0100 +++ b/OrthancServer/Database/SQLiteDatabaseWrapper.h Thu Jan 10 18:02:34 2019 +0100 @@ -353,5 +353,7 @@ { IGetChildrenMetadata::Apply(*this, target, resourceId, metadata); } + + virtual int64_t GetLastChangeIndex() ORTHANC_OVERRIDE; }; } diff -r b2b6db5ad9a5 -r 2e1711f80f74 OrthancServer/ServerIndex.cpp --- a/OrthancServer/ServerIndex.cpp Mon Jan 07 17:23:04 2019 +0100 +++ b/OrthancServer/ServerIndex.cpp Thu Jan 10 18:02:34 2019 +0100 @@ -1308,7 +1308,9 @@ const std::list& log, const std::string& name, bool done, - int64_t since) + int64_t since, + bool hasLast, + int64_t last) { Json::Value items = Json::arrayValue; for (typename std::list::const_iterator @@ -1323,7 +1325,19 @@ target[name] = items; target["Done"] = done; - int64_t last = (log.empty() ? since : log.back().GetSeq()); + if (!hasLast) + { + // Best-effort guess of the last index in the sequence + if (log.empty()) + { + last = since; + } + else + { + last = log.back().GetSeq(); + } + } + target["Last"] = static_cast(last); } @@ -1334,6 +1348,8 @@ { std::list changes; bool done; + bool hasLast = false; + int64_t last = 0; { boost::mutex::scoped_lock lock(mutex_); @@ -1341,17 +1357,26 @@ // Fix wrt. Orthanc <= 1.3.2: A transaction was missing, as // "GetLastChange()" involves calls to "GetPublicId()" Transaction transaction(*this); + db_.GetChanges(changes, done, since, maxResults); + if (changes.empty()) + { + last = db_.GetLastChangeIndex(); + hasLast = true; + } + transaction.Commit(0); } - FormatLog(target, changes, "Changes", done, since); + FormatLog(target, changes, "Changes", done, since, hasLast, last); } void ServerIndex::GetLastChange(Json::Value& target) { std::list changes; + bool hasLast = false; + int64_t last = 0; { boost::mutex::scoped_lock lock(mutex_); @@ -1359,11 +1384,18 @@ // Fix wrt. Orthanc <= 1.3.2: A transaction was missing, as // "GetLastChange()" involves calls to "GetPublicId()" Transaction transaction(*this); + db_.GetLastChange(changes); + if (changes.empty()) + { + last = db_.GetLastChangeIndex(); + hasLast = true; + } + transaction.Commit(0); } - FormatLog(target, changes, "Changes", true, 0); + FormatLog(target, changes, "Changes", true, 0, hasLast, last); } @@ -1469,7 +1501,7 @@ db_.GetExportedResources(exported, done, since, maxResults); } - FormatLog(target, exported, "Exports", done, since); + FormatLog(target, exported, "Exports", done, since, false, -1); } @@ -1482,7 +1514,7 @@ db_.GetLastExportedResource(exported); } - FormatLog(target, exported, "Exports", true, 0); + FormatLog(target, exported, "Exports", true, 0, false, -1); } diff -r b2b6db5ad9a5 -r 2e1711f80f74 Plugins/Engine/OrthancPluginDatabase.cpp --- a/Plugins/Engine/OrthancPluginDatabase.cpp Mon Jan 07 17:23:04 2019 +0100 +++ b/Plugins/Engine/OrthancPluginDatabase.cpp Thu Jan 10 18:02:34 2019 +0100 @@ -278,6 +278,11 @@ { LOG(WARNING) << "Performance warning in the database index: Some extensions are missing in the plugin"; } + + if (extensions_.getLastChangeIndex == NULL) + { + LOG(WARNING) << "The database extension GetLastChangeIndex() is missing"; + } } @@ -1392,4 +1397,21 @@ ForwardAnswers(target); } } + + + int64_t OrthancPluginDatabase::GetLastChangeIndex() + { + if (extensions_.getLastChangeIndex == NULL) + { + // This was the default behavior in Orthanc <= 1.5.1 + // https://groups.google.com/d/msg/orthanc-users/QhzB6vxYeZ0/YxabgqpfBAAJ + return 0; + } + else + { + int64_t result = 0; + CheckSuccess(extensions_.getLastChangeIndex(&result, payload_)); + return result; + } + } } diff -r b2b6db5ad9a5 -r 2e1711f80f74 Plugins/Engine/OrthancPluginDatabase.h --- a/Plugins/Engine/OrthancPluginDatabase.h Mon Jan 07 17:23:04 2019 +0100 +++ b/Plugins/Engine/OrthancPluginDatabase.h Thu Jan 10 18:02:34 2019 +0100 @@ -360,6 +360,8 @@ int64_t resourceId, MetadataType metadata) ORTHANC_OVERRIDE; + + virtual int64_t GetLastChangeIndex() ORTHANC_OVERRIDE; }; } diff -r b2b6db5ad9a5 -r 2e1711f80f74 Plugins/Include/orthanc/OrthancCDatabasePlugin.h --- a/Plugins/Include/orthanc/OrthancCDatabasePlugin.h Mon Jan 07 17:23:04 2019 +0100 +++ b/Plugins/Include/orthanc/OrthancCDatabasePlugin.h Thu Jan 10 18:02:34 2019 +0100 @@ -814,6 +814,12 @@ int64_t resourceId, int32_t metadata); + OrthancPluginErrorCode (*getLastChangeIndex) ( + /* outputs */ + int64_t* target, + /* inputs */ + void* payload); + } OrthancPluginDatabaseExtensions; /*