summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Vrátil <dvratil@kde.org>2016-09-30 15:28:19 (GMT)
committerDaniel Vrátil <dvratil@kde.org>2016-09-30 15:30:58 (GMT)
commitd263b9360093b4423c9521cc3e5096581490e3dd (patch)
tree93d3a3da0cc8fa25f630c36a868854f560d517c6
parent2aa2d64d7b45c792a26d8f5b71e635594f895c97 (diff)
Introduce concept of database generation
Generation is an integer which is guaranteed to never change as long as the database backend is not removed and re-created. If that happens it is guaranteed that the new generation identifier will be higher than the previous one. Client applications can access it via ServerManager::generation(). The purpose of the generation number is to make it possible for applications to detect when the database was recreated and some of their configuration must be invalidated (e.g. collection IDs stored in config files).
-rw-r--r--CMakeLists.txt2
-rw-r--r--autotests/server/fakeakonadiserver.cpp11
-rw-r--r--src/core/servermanager.cpp17
-rw-r--r--src/core/servermanager.h19
-rw-r--r--src/core/servermanager_p.h2
-rw-r--r--src/core/session.cpp3
-rw-r--r--src/private/protocol.cpp36
-rw-r--r--src/private/protocol_p.h4
-rw-r--r--src/server/connection.cpp11
-rw-r--r--src/server/notificationsubscriber.cpp11
-rw-r--r--src/server/storage/akonadidb.xml3
-rw-r--r--src/server/storage/dbinitializer.cpp11
12 files changed, 101 insertions, 29 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ce22d1d..d9381d8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -22,7 +22,7 @@ include(CheckSymbolExists)
include(AkonadiMacros)
-set(PIM_VERSION "5.3.45")
+set(PIM_VERSION "5.3.46")
set(QT_REQUIRED_VERSION "5.6.0")
set(AKONADI_VERSION ${PIM_VERSION})
diff --git a/autotests/server/fakeakonadiserver.cpp b/autotests/server/fakeakonadiserver.cpp
index 9d0f717..420a0e7 100644
--- a/autotests/server/fakeakonadiserver.cpp
+++ b/autotests/server/fakeakonadiserver.cpp
@@ -147,11 +147,14 @@ QString FakeAkonadiServer::instanceName()
TestScenario::List FakeAkonadiServer::loginScenario(const QByteArray &sessionId)
{
+ Protocol::HelloResponse hello;
+ hello.setServerName(QStringLiteral("Akonadi"));
+ hello.setMessage(QStringLiteral("Not really IMAP server"));
+ hello.setProtocolVersion(Protocol::version());
+ hello.setGeneration(1);
+
return {
- TestScenario::create(0, TestScenario::ServerCmd,
- Protocol::HelloResponse(QStringLiteral("Akonadi"),
- QStringLiteral("Not Really IMAP server"),
- Protocol::version())),
+ TestScenario::create(0, TestScenario::ServerCmd, hello),
TestScenario::create(1,TestScenario::ClientCmd,
Protocol::LoginCommand(sessionId.isEmpty() ? instanceName().toLatin1() : sessionId)),
TestScenario::create(1, TestScenario::ServerCmd,
diff --git a/src/core/servermanager.cpp b/src/core/servermanager.cpp
index 219a7df..f078553 100644
--- a/src/core/servermanager.cpp
+++ b/src/core/servermanager.cpp
@@ -118,6 +118,7 @@ public:
ServerManager *instance;
static int serverProtocolVersion;
+ static uint generation;
ServerManager::State mState;
QScopedPointer<QTimer> mSafetyTimer;
Firstrun *mFirstRunner;
@@ -125,6 +126,7 @@ public:
};
int ServerManagerPrivate::serverProtocolVersion = -1;
+uint ServerManagerPrivate::generation = 0;
Internal::ClientType ServerManagerPrivate::clientType = Internal::User;
Q_GLOBAL_STATIC(ServerManagerPrivate, sInstance)
@@ -351,6 +353,11 @@ QString ServerManager::addNamespace(const QString &string)
return string;
}
+uint ServerManager::generation()
+{
+ return Internal::generation();
+}
+
int Internal::serverProtocolVersion()
{
return ServerManagerPrivate::serverProtocolVersion;
@@ -364,6 +371,16 @@ void Internal::setServerProtocolVersion(int version)
}
}
+uint Internal::generation()
+{
+ return ServerManagerPrivate::generation;
+}
+
+void Internal::setGeneration(uint generation)
+{
+ ServerManagerPrivate::generation = generation;
+}
+
Internal::ClientType Internal::clientType()
{
return ServerManagerPrivate::clientType;
diff --git a/src/core/servermanager.h b/src/core/servermanager.h
index 282892e..8031d1d 100644
--- a/src/core/servermanager.h
+++ b/src/core/servermanager.h
@@ -178,6 +178,25 @@ public:
*/
static QString agentConfigFilePath(const QString &identifier);
+ /**
+ * Returns current Akonadi database generation identifier
+ *
+ * Generation is guaranteed to never change unless as long as the database
+ * backend is not removed and re-created. In such case it is guaranteed that
+ * the new generation number will be higher than the previous one.
+ *
+ * Generation can be used by applications to detect when Akonadi database
+ * has been recreated and thus some of the configuration (for example
+ * collection IDs stored in a config file) must be invalidated.
+ *
+ * @note Note that the generation number is only available if the server
+ * is running. If this function is called before the server starts it will
+ * return 0.
+ *
+ * @since 5.4
+ */
+ static uint generation();
+
Q_SIGNALS:
/**
* Emitted whenever the server becomes fully operational.
diff --git a/src/core/servermanager_p.h b/src/core/servermanager_p.h
index 85f17b6..370d252 100644
--- a/src/core/servermanager_p.h
+++ b/src/core/servermanager_p.h
@@ -32,6 +32,8 @@ namespace Internal
AKONADICORE_EXPORT int serverProtocolVersion();
AKONADICORE_EXPORT void setServerProtocolVersion(int version);
+AKONADICORE_EXPORT uint generation();
+AKONADICORE_EXPORT void setGeneration(uint generation);
enum ClientType {
User,
diff --git a/src/core/session.cpp b/src/core/session.cpp
index 7545acc..6a96668 100644
--- a/src/core/session.cpp
+++ b/src/core/session.cpp
@@ -111,11 +111,14 @@ bool SessionPrivate::handleCommand(qint64 tag, const Protocol::Command &cmd)
}
qCDebug(AKONADICORE_LOG) << "Connected to" << hello.serverName() << ", using protocol version" << hello.protocolVersion();
+ qCDebug(AKONADICORE_LOG) << "Server generation:" << hello.generation();
qCDebug(AKONADICORE_LOG) << "Server says:" << hello.message();
// Version mismatch is handled in SessionPrivate::startJob() so that
// we can report the error out via KJob API
protocolVersion = hello.protocolVersion();
Internal::setServerProtocolVersion(protocolVersion);
+ Internal::setGeneration(hello.generation());
+
Protocol::LoginCommand login(sessionId);
sendCommand(nextTag(), login);
diff --git a/src/private/protocol.cpp b/src/private/protocol.cpp
index 3597879..ecb7cb0 100644
--- a/src/private/protocol.cpp
+++ b/src/private/protocol.cpp
@@ -49,7 +49,7 @@ namespace Akonadi {
namespace Protocol {
int version() {
- return 55;
+ return 56;
}
}
@@ -1533,12 +1533,7 @@ public:
HelloResponsePrivate()
: ResponsePrivate(Command::Hello)
, protocol(0)
- {}
- HelloResponsePrivate(const QString &server, const QString &message, int protocol)
- : ResponsePrivate(Command::Hello)
- , server(server)
- , message(message)
- , protocol(protocol)
+ , generation(0)
{}
HelloResponsePrivate(const HelloResponsePrivate &other)
@@ -1546,6 +1541,7 @@ public:
, server(other.server)
, message(other.message)
, protocol(other.protocol)
+ , generation(other.generation)
{}
bool compare(const CommandPrivate *other) const Q_DECL_OVERRIDE
@@ -1553,7 +1549,8 @@ public:
return ResponsePrivate::compare(other)
&& COMPARE(server)
&& COMPARE(message)
- && COMPARE(protocol);
+ && COMPARE(protocol)
+ && COMPARE(generation);
}
DataStream &serialize(DataStream &stream) const Q_DECL_OVERRIDE
@@ -1561,7 +1558,8 @@ public:
return ResponsePrivate::serialize(stream)
<< server
<< message
- << protocol;
+ << protocol
+ << generation;
}
DataStream &deserialize(DataStream &stream) Q_DECL_OVERRIDE
@@ -1569,7 +1567,8 @@ public:
return ResponsePrivate::deserialize(stream)
>> server
>> message
- >> protocol;
+ >> protocol
+ >> generation;
}
void debugString(DebugBlock &blck) const Q_DECL_OVERRIDE
@@ -1578,6 +1577,7 @@ public:
blck.write("Server", server);
blck.write("Protocol Version", protocol);
blck.write("Message", message);
+ blck.write("Generation", generation);
}
CommandPrivate *clone() const Q_DECL_OVERRIDE
@@ -1588,6 +1588,7 @@ public:
QString server;
QString message;
int protocol;
+ uint generation;
};
@@ -1602,11 +1603,6 @@ public:
AKONADI_DECLARE_PRIVATE(HelloResponse)
-HelloResponse::HelloResponse(const QString &server, const QString &message, int protocol)
- : Response(new HelloResponsePrivate(server, message, protocol))
-{
-}
-
HelloResponse::HelloResponse()
: Response(new HelloResponsePrivate)
{
@@ -1648,6 +1644,16 @@ int HelloResponse::protocolVersion() const
return d_func()->protocol;
}
+void HelloResponse::setGeneration(uint generation)
+{
+ d_func()->generation = generation;
+}
+
+uint HelloResponse::generation() const
+{
+ return d_func()->generation;
+}
+
DataStream &operator<<(DataStream &stream, const HelloResponse &command)
{
return command.d_func()->serialize(stream);
diff --git a/src/private/protocol_p.h b/src/private/protocol_p.h
index 97ec4ef..4da44cc 100644
--- a/src/private/protocol_p.h
+++ b/src/private/protocol_p.h
@@ -476,7 +476,6 @@ class AKONADIPRIVATE_EXPORT HelloResponse : public Response
public:
explicit HelloResponse();
explicit HelloResponse(const Command &command);
- HelloResponse(const QString &server, const QString &message, int protocol);
void setServerName(const QString &server);
QString serverName() const;
@@ -487,6 +486,9 @@ public:
void setProtocolVersion(int protocolVersion);
int protocolVersion() const;
+ void setGeneration(uint generation);
+ uint generation() const;
+
private:
AKONADI_DECLARE_PRIVATE(HelloResponse)
diff --git a/src/server/connection.cpp b/src/server/connection.cpp
index 0344107..a77d1e4 100644
--- a/src/server/connection.cpp
+++ b/src/server/connection.cpp
@@ -121,9 +121,14 @@ void Connection::quit()
void Connection::slotSendHello()
{
- sendResponse(0, Protocol::HelloResponse(QStringLiteral("Akonadi"),
- QStringLiteral("Not Really IMAP server"),
- Protocol::version()));
+ SchemaVersion version = SchemaVersion::retrieveAll().first();
+
+ Protocol::HelloResponse hello;
+ hello.setServerName(QStringLiteral("Akonadi"));
+ hello.setMessage(QStringLiteral("Not Really IMAP server"));
+ hello.setProtocolVersion(Protocol::version());
+ hello.setGeneration(version.generation());
+ sendResponse(0, hello);
}
DataStore *Connection::storageBackend()
diff --git a/src/server/notificationsubscriber.cpp b/src/server/notificationsubscriber.cpp
index ca33c96..ed5d348 100644
--- a/src/server/notificationsubscriber.cpp
+++ b/src/server/notificationsubscriber.cpp
@@ -58,9 +58,14 @@ NotificationSubscriber::NotificationSubscriber(NotificationManager *manager, qui
this, &NotificationSubscriber::socketDisconnected);
mSocket->setSocketDescriptor(socketDescriptor);
- writeCommand(0, Protocol::HelloResponse(QStringLiteral("Akonadi"),
- QStringLiteral("Not-really IMAP server"),
- Protocol::version()));
+ const SchemaVersion schema = SchemaVersion::retrieveAll().first();
+
+ Protocol::HelloResponse hello;
+ hello.setServerName(QStringLiteral("Akonadi"));
+ hello.setMessage(QStringLiteral("Not really IMAP server"));
+ hello.setProtocolVersion(Protocol::version());
+ hello.setGeneration(schema.generation());
+ writeCommand(0, hello);
}
NotificationSubscriber::~NotificationSubscriber()
diff --git a/src/server/storage/akonadidb.xml b/src/server/storage/akonadidb.xml
index ed71af9..a3646ee 100644
--- a/src/server/storage/akonadidb.xml
+++ b/src/server/storage/akonadidb.xml
@@ -66,7 +66,8 @@
<table name="SchemaVersion">
<comment>Contains the schema version of the database.</comment>
<column name="version" type="int" default="0" allowNull="false"/>
- <data columns="version" values="33"/>
+ <column name="generation" type="int" default="0" allowNull="false" />
+ <data columns="version" values="34"/>
</table>
<table name="Resource">
diff --git a/src/server/storage/dbinitializer.cpp b/src/server/storage/dbinitializer.cpp
index 572ee53..f2d840a 100644
--- a/src/server/storage/dbinitializer.cpp
+++ b/src/server/storage/dbinitializer.cpp
@@ -23,7 +23,7 @@
#include "querybuilder.h"
#include "dbexception.h"
#include "schema.h"
-#include "entity.h"
+#include "entities.h"
#include "akonadiserver_debug.h"
#include <QtCore/QFile>
@@ -92,6 +92,15 @@ bool DbInitializer::run()
}
}
+ // Now finally check and set the generation identifier if necessary
+ SchemaVersion version = SchemaVersion::retrieveAll().first();
+ if (version.generation() == 0) {
+ version.setGeneration(QDateTime::currentDateTimeUtc().toTime_t());
+ version.update();
+
+ qCDebug(AKONADISERVER_LOG) << "Generation:" << version.generation();
+ }
+
qCDebug(AKONADISERVER_LOG) << "DbInitializer::run() done";
return true;
} catch (const DbException &e) {