From 436cb365db846985ef5ce508cb5bf925cd903480 Mon Sep 17 00:00:00 2001 From: Janne Koschinski Date: Sat, 3 Mar 2018 08:45:31 +0100 Subject: [PATCH] core: Store session state in database, migrate old Store core session state in database rather than configuration file. This improves containerization as the configuration file doesn't need to be preserved, and also makes database restoration handle restoring active sessions. Migrate existing legacy sessions to database storage, ensuring that the core state fallback is handled correctly, too. Part of GH-341. --- src/core/SQL/PostgreSQL/insert_core_state.sql | 2 + .../PostgreSQL/migrate_write_corestate.sql | 2 + src/core/SQL/PostgreSQL/select_core_state.sql | 3 + .../SQL/PostgreSQL/setup_150_corestate.sql | 5 ++ src/core/SQL/PostgreSQL/update_core_state.sql | 3 + .../28/upgrade_000_create_corestate.sql | 5 ++ src/core/SQL/SQLite/insert_core_state.sql | 2 + .../SQL/SQLite/migrate_read_corestate.sql | 3 + src/core/SQL/SQLite/select_core_state.sql | 3 + src/core/SQL/SQLite/setup_160_corestate.sql | 5 ++ src/core/SQL/SQLite/update_core_state.sql | 3 + .../30/upgrade_000_create_corestate.sql | 5 ++ src/core/abstractsqlstorage.cpp | 6 ++ src/core/abstractsqlstorage.h | 10 ++- src/core/core.cpp | 10 ++- src/core/postgresqlstorage.cpp | 62 +++++++++++++++++ src/core/postgresqlstorage.h | 3 + src/core/sql.qrc | 12 ++++ src/core/sqlitestorage.cpp | 69 +++++++++++++++++++ src/core/sqlitestorage.h | 3 + src/core/storage.h | 13 ++++ 21 files changed, 222 insertions(+), 7 deletions(-) create mode 100644 src/core/SQL/PostgreSQL/insert_core_state.sql create mode 100644 src/core/SQL/PostgreSQL/migrate_write_corestate.sql create mode 100644 src/core/SQL/PostgreSQL/select_core_state.sql create mode 100644 src/core/SQL/PostgreSQL/setup_150_corestate.sql create mode 100644 src/core/SQL/PostgreSQL/update_core_state.sql create mode 100644 src/core/SQL/PostgreSQL/version/28/upgrade_000_create_corestate.sql create mode 100644 src/core/SQL/SQLite/insert_core_state.sql create mode 100644 src/core/SQL/SQLite/migrate_read_corestate.sql create mode 100644 src/core/SQL/SQLite/select_core_state.sql create mode 100644 src/core/SQL/SQLite/setup_160_corestate.sql create mode 100644 src/core/SQL/SQLite/update_core_state.sql create mode 100644 src/core/SQL/SQLite/version/30/upgrade_000_create_corestate.sql diff --git a/src/core/SQL/PostgreSQL/insert_core_state.sql b/src/core/SQL/PostgreSQL/insert_core_state.sql new file mode 100644 index 00000000..899fc045 --- /dev/null +++ b/src/core/SQL/PostgreSQL/insert_core_state.sql @@ -0,0 +1,2 @@ +INSERT INTO core_state (key, value) +VALUES (:key, :value) diff --git a/src/core/SQL/PostgreSQL/migrate_write_corestate.sql b/src/core/SQL/PostgreSQL/migrate_write_corestate.sql new file mode 100644 index 00000000..877822df --- /dev/null +++ b/src/core/SQL/PostgreSQL/migrate_write_corestate.sql @@ -0,0 +1,2 @@ +INSERT INTO core_state (key, value) +VALUES (?, ?) diff --git a/src/core/SQL/PostgreSQL/select_core_state.sql b/src/core/SQL/PostgreSQL/select_core_state.sql new file mode 100644 index 00000000..37565cec --- /dev/null +++ b/src/core/SQL/PostgreSQL/select_core_state.sql @@ -0,0 +1,3 @@ +SELECT value +FROM core_state +WHERE key = :key diff --git a/src/core/SQL/PostgreSQL/setup_150_corestate.sql b/src/core/SQL/PostgreSQL/setup_150_corestate.sql new file mode 100644 index 00000000..a26d8524 --- /dev/null +++ b/src/core/SQL/PostgreSQL/setup_150_corestate.sql @@ -0,0 +1,5 @@ +CREATE TABLE core_state ( + key TEXT NOT NULL, + value bytea, + PRIMARY KEY (key) +) diff --git a/src/core/SQL/PostgreSQL/update_core_state.sql b/src/core/SQL/PostgreSQL/update_core_state.sql new file mode 100644 index 00000000..922dc95a --- /dev/null +++ b/src/core/SQL/PostgreSQL/update_core_state.sql @@ -0,0 +1,3 @@ +UPDATE core_state +SET value = :value +WHERE key = :key diff --git a/src/core/SQL/PostgreSQL/version/28/upgrade_000_create_corestate.sql b/src/core/SQL/PostgreSQL/version/28/upgrade_000_create_corestate.sql new file mode 100644 index 00000000..a26d8524 --- /dev/null +++ b/src/core/SQL/PostgreSQL/version/28/upgrade_000_create_corestate.sql @@ -0,0 +1,5 @@ +CREATE TABLE core_state ( + key TEXT NOT NULL, + value bytea, + PRIMARY KEY (key) +) diff --git a/src/core/SQL/SQLite/insert_core_state.sql b/src/core/SQL/SQLite/insert_core_state.sql new file mode 100644 index 00000000..899fc045 --- /dev/null +++ b/src/core/SQL/SQLite/insert_core_state.sql @@ -0,0 +1,2 @@ +INSERT INTO core_state (key, value) +VALUES (:key, :value) diff --git a/src/core/SQL/SQLite/migrate_read_corestate.sql b/src/core/SQL/SQLite/migrate_read_corestate.sql new file mode 100644 index 00000000..0bc5366b --- /dev/null +++ b/src/core/SQL/SQLite/migrate_read_corestate.sql @@ -0,0 +1,3 @@ +SELECT key, value +FROM core_state + diff --git a/src/core/SQL/SQLite/select_core_state.sql b/src/core/SQL/SQLite/select_core_state.sql new file mode 100644 index 00000000..37565cec --- /dev/null +++ b/src/core/SQL/SQLite/select_core_state.sql @@ -0,0 +1,3 @@ +SELECT value +FROM core_state +WHERE key = :key diff --git a/src/core/SQL/SQLite/setup_160_corestate.sql b/src/core/SQL/SQLite/setup_160_corestate.sql new file mode 100644 index 00000000..a26d8524 --- /dev/null +++ b/src/core/SQL/SQLite/setup_160_corestate.sql @@ -0,0 +1,5 @@ +CREATE TABLE core_state ( + key TEXT NOT NULL, + value bytea, + PRIMARY KEY (key) +) diff --git a/src/core/SQL/SQLite/update_core_state.sql b/src/core/SQL/SQLite/update_core_state.sql new file mode 100644 index 00000000..922dc95a --- /dev/null +++ b/src/core/SQL/SQLite/update_core_state.sql @@ -0,0 +1,3 @@ +UPDATE core_state +SET value = :value +WHERE key = :key diff --git a/src/core/SQL/SQLite/version/30/upgrade_000_create_corestate.sql b/src/core/SQL/SQLite/version/30/upgrade_000_create_corestate.sql new file mode 100644 index 00000000..a26d8524 --- /dev/null +++ b/src/core/SQL/SQLite/version/30/upgrade_000_create_corestate.sql @@ -0,0 +1,5 @@ +CREATE TABLE core_state ( + key TEXT NOT NULL, + value bytea, + PRIMARY KEY (key) +) diff --git a/src/core/abstractsqlstorage.cpp b/src/core/abstractsqlstorage.cpp index 4ecf623b..cb8fbd11 100644 --- a/src/core/abstractsqlstorage.cpp +++ b/src/core/abstractsqlstorage.cpp @@ -409,6 +409,8 @@ QString AbstractSqlMigrator::migrationObject(MigrationObject moType) return "IrcServer"; case UserSetting: return "UserSetting"; + case CoreState: + return "CoreState"; }; return QString(); } @@ -502,6 +504,10 @@ bool AbstractSqlMigrationReader::migrateTo(AbstractSqlMigrationWriter *writer) if (!transferMo(UserSetting, userSettingMo)) return false; + CoreStateMO coreStateMO; + if (!transferMo(CoreState, coreStateMO)) + return false; + if (!_writer->postProcess()) abortMigration(); return finalizeMigration(); diff --git a/src/core/abstractsqlstorage.h b/src/core/abstractsqlstorage.h index 2e572307..e8945551 100644 --- a/src/core/abstractsqlstorage.h +++ b/src/core/abstractsqlstorage.h @@ -285,6 +285,11 @@ public: QByteArray settingvalue; }; + struct CoreStateMO { + QString key; + QByteArray value; + }; + enum MigrationObject { QuasselUser, Sender, @@ -294,7 +299,8 @@ public: Buffer, Backlog, IrcServer, - UserSetting + UserSetting, + CoreState }; AbstractSqlMigrator(); @@ -340,6 +346,7 @@ public: virtual bool readMo(BacklogMO &backlog) = 0; virtual bool readMo(IrcServerMO &ircserver) = 0; virtual bool readMo(UserSettingMO &userSetting) = 0; + virtual bool readMo(CoreStateMO &coreState) = 0; bool migrateTo(AbstractSqlMigrationWriter *writer); @@ -365,6 +372,7 @@ public: virtual bool writeMo(const BacklogMO &backlog) = 0; virtual bool writeMo(const IrcServerMO &ircserver) = 0; virtual bool writeMo(const UserSettingMO &userSetting) = 0; + virtual bool writeMo(const CoreStateMO &coreState) = 0; inline bool migrateFrom(AbstractSqlMigrationReader *reader) { return reader->migrateTo(this); } diff --git a/src/core/core.cpp b/src/core/core.cpp index aecb06e3..7fbd4e71 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -259,14 +259,10 @@ Core::~Core() void Core::saveState() { - CoreSettings s; - QVariantMap state; QVariantList activeSessions; foreach(UserId user, instance()->_sessions.keys()) activeSessions << QVariant::fromValue(user); - state["CoreStateVersion"] = 1; - state["ActiveSessions"] = activeSessions; - s.setCoreState(state); + instance()->_storage->setCoreState(activeSessions); } @@ -289,7 +285,9 @@ void Core::restoreState() } */ - QVariantList activeSessions = s.coreState().toMap()["ActiveSessions"].toList(); + const QList &activeSessionsFallback = s.coreState().toMap()["ActiveSessions"].toList(); + QVariantList activeSessions = instance()->_storage->getCoreState(activeSessionsFallback); + if (activeSessions.count() > 0) { quInfo() << "Restoring previous core state..."; foreach(QVariant v, activeSessions) { diff --git a/src/core/postgresqlstorage.cpp b/src/core/postgresqlstorage.cpp index 5b52afd6..a6f2a72c 100644 --- a/src/core/postgresqlstorage.cpp +++ b/src/core/postgresqlstorage.cpp @@ -397,6 +397,58 @@ QVariant PostgreSqlStorage::getUserSetting(UserId userId, const QString &setting } +void PostgreSqlStorage::setCoreState(const QVariantList &data) +{ + QByteArray rawData; + QDataStream out(&rawData, QIODevice::WriteOnly); + out.setVersion(QDataStream::Qt_4_2); + out << data; + + QSqlDatabase db = logDb(); + QSqlQuery selectQuery(db); + selectQuery.prepare(queryString("select_core_state")); + selectQuery.bindValue(":key", "active_sessions"); + safeExec(selectQuery); + watchQuery(selectQuery); + + QString setQueryString; + if (!selectQuery.first()) { + setQueryString = queryString("insert_core_state"); + } + else { + setQueryString = queryString("update_core_state"); + } + + QSqlQuery setQuery(db); + setQuery.prepare(setQueryString); + setQuery.bindValue(":key", "active_sessions"); + setQuery.bindValue(":value", rawData); + safeExec(setQuery); + watchQuery(setQuery); +} + + +QVariantList PostgreSqlStorage::getCoreState(const QVariantList &defaultData) +{ + QSqlQuery query(logDb()); + query.prepare(queryString("select_core_state")); + query.bindValue(":key", "active_sessions"); + safeExec(query); + watchQuery(query); + + if (query.first()) { + QVariantList data; + QByteArray rawData = query.value(0).toByteArray(); + QDataStream in(&rawData, QIODevice::ReadOnly); + in.setVersion(QDataStream::Qt_4_2); + in >> data; + return data; + } else { + return defaultData; + } +} + + IdentityId PostgreSqlStorage::createIdentity(UserId user, CoreIdentity &identity) { IdentityId identityId; @@ -2176,6 +2228,9 @@ bool PostgreSqlMigrationWriter::prepareQuery(MigrationObject mo) case UserSetting: query = queryString("migrate_write_usersetting"); break; + case CoreState: + query = queryString("migrate_write_corestate"); + break; } newQuery(query, logDb()); return true; @@ -2352,6 +2407,13 @@ bool PostgreSqlMigrationWriter::writeMo(const UserSettingMO &userSetting) return exec(); } +bool PostgreSqlMigrationWriter::writeMo(const CoreStateMO &coreState) +{ + bindValue(0, coreState.key); + bindValue(1, coreState.value); + return exec(); +} + bool PostgreSqlMigrationWriter::postProcess() { diff --git a/src/core/postgresqlstorage.h b/src/core/postgresqlstorage.h index e9fc8740..1c6afbac 100644 --- a/src/core/postgresqlstorage.h +++ b/src/core/postgresqlstorage.h @@ -57,6 +57,8 @@ public slots: void delUser(UserId user) override; void setUserSetting(UserId userId, const QString &settingName, const QVariant &data) override; QVariant getUserSetting(UserId userId, const QString &settingName, const QVariant &defaultData = QVariant()) override; + void setCoreState(const QVariantList &data) override; + QVariantList getCoreState(const QVariantList &data) override; /* Identity handling */ IdentityId createIdentity(UserId user, CoreIdentity &identity) override; @@ -178,6 +180,7 @@ public: bool writeMo(const BacklogMO &backlog) override; bool writeMo(const IrcServerMO &ircserver) override; bool writeMo(const UserSettingMO &userSetting) override; + bool writeMo(const CoreStateMO &coreState) override; bool prepareQuery(MigrationObject mo) override; diff --git a/src/core/sql.qrc b/src/core/sql.qrc index c90d472f..d9578c04 100644 --- a/src/core/sql.qrc +++ b/src/core/sql.qrc @@ -13,6 +13,7 @@ ./SQL/PostgreSQL/delete_nicks.sql ./SQL/PostgreSQL/delete_quasseluser.sql ./SQL/PostgreSQL/insert_buffer.sql + ./SQL/PostgreSQL/insert_core_state.sql ./SQL/PostgreSQL/insert_identity.sql ./SQL/PostgreSQL/insert_message.sql ./SQL/PostgreSQL/insert_network.sql @@ -23,6 +24,7 @@ ./SQL/PostgreSQL/insert_user_setting.sql ./SQL/PostgreSQL/migrate_write_backlog.sql ./SQL/PostgreSQL/migrate_write_buffer.sql + ./SQL/PostgreSQL/migrate_write_corestate.sql ./SQL/PostgreSQL/migrate_write_identity.sql ./SQL/PostgreSQL/migrate_write_identity_nick.sql ./SQL/PostgreSQL/migrate_write_ircserver.sql @@ -48,6 +50,7 @@ ./SQL/PostgreSQL/select_buffers_for_network.sql ./SQL/PostgreSQL/select_checkidentity.sql ./SQL/PostgreSQL/select_connected_networks.sql + ./SQL/PostgreSQL/select_core_state.sql ./SQL/PostgreSQL/select_identities.sql ./SQL/PostgreSQL/select_internaluser.sql ./SQL/PostgreSQL/select_messagesAll.sql @@ -87,6 +90,7 @@ ./SQL/PostgreSQL/setup_120_alter_messageid_seq.sql ./SQL/PostgreSQL/setup_130_function_lastmsgid.sql ./SQL/PostgreSQL/setup_140_sender_idx.sql + ./SQL/PostgreSQL/setup_150_corestate.sql ./SQL/PostgreSQL/update_backlog_bufferid.sql ./SQL/PostgreSQL/update_buffer_bufferactivity.sql ./SQL/PostgreSQL/update_buffer_cipher.sql @@ -96,6 +100,7 @@ ./SQL/PostgreSQL/update_buffer_name.sql ./SQL/PostgreSQL/update_buffer_persistent_channel.sql ./SQL/PostgreSQL/update_buffer_set_channel_key.sql + ./SQL/PostgreSQL/update_core_state.sql ./SQL/PostgreSQL/update_identity.sql ./SQL/PostgreSQL/update_network.sql ./SQL/PostgreSQL/update_network_connected.sql @@ -128,6 +133,7 @@ ./SQL/PostgreSQL/version/27/upgrade_010_update_sender_add_avatarurl.sql ./SQL/PostgreSQL/version/27/upgrade_020_update_sender_add_new_constraint.sql ./SQL/PostgreSQL/version/27/upgrade_030_upgrade_sender_drop_old_constraint.sql + ./SQL/PostgreSQL/version/28/upgrade_000_create_corestate.sql ./SQL/SQLite/delete_backlog_by_uid.sql ./SQL/SQLite/delete_backlog_for_buffer.sql ./SQL/SQLite/delete_backlog_for_network.sql @@ -141,6 +147,7 @@ ./SQL/SQLite/delete_nicks.sql ./SQL/SQLite/delete_quasseluser.sql ./SQL/SQLite/insert_buffer.sql + ./SQL/SQLite/insert_core_state.sql ./SQL/SQLite/insert_identity.sql ./SQL/SQLite/insert_message.sql ./SQL/SQLite/insert_network.sql @@ -151,6 +158,7 @@ ./SQL/SQLite/insert_user_setting.sql ./SQL/SQLite/migrate_read_backlog.sql ./SQL/SQLite/migrate_read_buffer.sql + ./SQL/SQLite/migrate_read_corestate.sql ./SQL/SQLite/migrate_read_identity.sql ./SQL/SQLite/migrate_read_identity_nick.sql ./SQL/SQLite/migrate_read_ircserver.sql @@ -177,6 +185,7 @@ ./SQL/SQLite/select_buffers_for_network.sql ./SQL/SQLite/select_checkidentity.sql ./SQL/SQLite/select_connected_networks.sql + ./SQL/SQLite/select_core_state.sql ./SQL/SQLite/select_identities.sql ./SQL/SQLite/select_internaluser.sql ./SQL/SQLite/select_messagesAll.sql @@ -217,6 +226,7 @@ ./SQL/SQLite/setup_130_identity.sql ./SQL/SQLite/setup_140_identity_nick.sql ./SQL/SQLite/setup_150_sender_idx.sql + ./SQL/SQLite/setup_160_corestate.sql ./SQL/SQLite/update_backlog_bufferid.sql ./SQL/SQLite/update_buffer_bufferactivity.sql ./SQL/SQLite/update_buffer_cipher.sql @@ -226,6 +236,7 @@ ./SQL/SQLite/update_buffer_name.sql ./SQL/SQLite/update_buffer_persistent_channel.sql ./SQL/SQLite/update_buffer_set_channel_key.sql + ./SQL/SQLite/update_core_state.sql ./SQL/SQLite/update_identity.sql ./SQL/SQLite/update_network.sql ./SQL/SQLite/update_network_connected.sql @@ -332,5 +343,6 @@ ./SQL/SQLite/version/29/upgrade_020_drop_sender.sql ./SQL/SQLite/version/29/upgrade_030_rename_sender_tmp_sender.sql ./SQL/SQLite/version/29/upgrade_040_update_sender_add_realname_avatarurl.sql + ./SQL/SQLite/version/30/upgrade_000_create_corestate.sql diff --git a/src/core/sqlitestorage.cpp b/src/core/sqlitestorage.cpp index 5139d387..76940217 100644 --- a/src/core/sqlitestorage.cpp +++ b/src/core/sqlitestorage.cpp @@ -376,6 +376,60 @@ QVariant SqliteStorage::getUserSetting(UserId userId, const QString &settingName } +void SqliteStorage::setCoreState(const QVariantList &data) +{ + QByteArray rawData; + QDataStream out(&rawData, QIODevice::WriteOnly); + out.setVersion(QDataStream::Qt_4_2); + out << data; + + QSqlDatabase db = logDb(); + db.transaction(); + { + QSqlQuery query(db); + query.prepare(queryString("insert_core_state")); + query.bindValue(":key", "active_sessions"); + query.bindValue(":value", rawData); + lockForWrite(); + safeExec(query); + + if (query.lastError().isValid()) { + QSqlQuery updateQuery(db); + updateQuery.prepare(queryString("update_core_state")); + updateQuery.bindValue(":key", "active_sessions"); + updateQuery.bindValue(":value", rawData); + safeExec(updateQuery); + } + db.commit(); + } + unlock(); +} + + +QVariantList SqliteStorage::getCoreState(const QVariantList &defaultData) +{ + QVariantList data; + { + QSqlQuery query(logDb()); + query.prepare(queryString("select_core_state")); + query.bindValue(":key", "active_sessions"); + lockForRead(); + safeExec(query); + + if (query.first()) { + QByteArray rawData = query.value(0).toByteArray(); + QDataStream in(&rawData, QIODevice::ReadOnly); + in.setVersion(QDataStream::Qt_4_2); + in >> data; + } else { + data = defaultData; + } + } + unlock(); + return data; +} + + IdentityId SqliteStorage::createIdentity(UserId user, CoreIdentity &identity) { IdentityId identityId; @@ -2220,6 +2274,9 @@ bool SqliteMigrationReader::prepareQuery(MigrationObject mo) case UserSetting: newQuery(queryString("migrate_read_usersetting"), logDb()); break; + case CoreState: + newQuery(queryString("migrate_read_corestate"), logDb()); + break; } return exec(); } @@ -2431,3 +2488,15 @@ bool SqliteMigrationReader::readMo(UserSettingMO &userSetting) return true; } + + +bool SqliteMigrationReader::readMo(CoreStateMO &coreState) +{ + if (!next()) + return false; + + coreState.key = value(0).toString(); + coreState.value = value(1).toByteArray(); + + return true; +} diff --git a/src/core/sqlitestorage.h b/src/core/sqlitestorage.h index 41312f12..5d396ad5 100644 --- a/src/core/sqlitestorage.h +++ b/src/core/sqlitestorage.h @@ -58,6 +58,8 @@ public slots: void delUser(UserId user) override; void setUserSetting(UserId userId, const QString &settingName, const QVariant &data) override; QVariant getUserSetting(UserId userId, const QString &settingName, const QVariant &defaultData = QVariant()) override; + void setCoreState(const QVariantList &data) override; + QVariantList getCoreState(const QVariantList &data) override; /* Identity handling */ IdentityId createIdentity(UserId user, CoreIdentity &identity) override; @@ -162,6 +164,7 @@ public: bool readMo(BacklogMO &backlog) override; bool readMo(IrcServerMO &ircserver) override; bool readMo(UserSettingMO &userSetting) override; + bool readMo(CoreStateMO &coreState) override; bool prepareQuery(MigrationObject mo) override; diff --git a/src/core/storage.h b/src/core/storage.h index 7cbc3e3d..5a0a6405 100644 --- a/src/core/storage.h +++ b/src/core/storage.h @@ -171,6 +171,19 @@ public slots: */ virtual QVariant getUserSetting(UserId userId, const QString &settingName, const QVariant &data = QVariant()) = 0; + //! Store core state + /** + * \param data Active Sessions + */ + virtual void setCoreState(const QVariantList &data) = 0; + + //! Retrieve core state + /** + * \param default Value to return in case it's unset. + * \return Active Sessions + */ + virtual QVariantList getCoreState(const QVariantList &data = QVariantList()) = 0; + /* Identity handling */ virtual IdentityId createIdentity(UserId user, CoreIdentity &identity) = 0; virtual bool updateIdentity(UserId user, const CoreIdentity &identity) = 0; -- 2.20.1