From dad2de7ba2323ff0f5c229968ec95f05b10b6f45 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 2 May 2020 16:44:50 +0200 Subject: Add support for db migrations --- src/Cache.cpp | 36 ++++++++++++++++++++++++------------ src/Cache.h | 9 +++++++-- src/CacheStructs.h | 9 +++++++++ src/Cache_p.h | 3 ++- src/ChatPage.cpp | 40 +++++++++++++++++++++++++++++----------- 5 files changed, 71 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/Cache.cpp b/src/Cache.cpp index eb5c93aa..1a097cff 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -665,8 +665,15 @@ Cache::deleteData() } } +//! migrates db to the current format bool -Cache::isFormatValid() +Cache::runMigrations() +{ + return true; +} + +cache::CacheVersion +Cache::formatVersion() { auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY); @@ -676,18 +683,16 @@ Cache::isFormatValid() txn.commit(); if (!res) - return false; + return cache::CacheVersion::Older; std::string stored_version(current_version.data(), current_version.size()); - if (stored_version != CURRENT_CACHE_FORMAT_VERSION) { - nhlog::db()->warn("breaking changes in the cache format. stored: {}, current: {}", - stored_version, - CURRENT_CACHE_FORMAT_VERSION); - return false; - } - - return true; + if (stored_version < CURRENT_CACHE_FORMAT_VERSION) + return cache::CacheVersion::Older; + else if (stored_version > CURRENT_CACHE_FORMAT_VERSION) + return cache::CacheVersion::Older; + else + return cache::CacheVersion::Current; } void @@ -2468,10 +2473,17 @@ setup() } bool -isFormatValid() +runMigrations() +{ + return instance_->runMigrations(); +} + +cache::CacheVersion +formatVersion() { - return instance_->isFormatValid(); + return instance_->formatVersion(); } + void setCurrentFormat() { diff --git a/src/Cache.h b/src/Cache.h index 99c63550..12465c9d 100644 --- a/src/Cache.h +++ b/src/Cache.h @@ -111,10 +111,15 @@ removeRoom(const QString &roomid); void setup(); -bool -isFormatValid(); +//! returns if the format is current, older or newer +cache::CacheVersion +formatVersion(); +//! set the format version to the current version void setCurrentFormat(); +//! migrates db to the current format +bool +runMigrations(); std::map roomMessages(); diff --git a/src/CacheStructs.h b/src/CacheStructs.h index ab7bbc71..ef08cfcb 100644 --- a/src/CacheStructs.h +++ b/src/CacheStructs.h @@ -8,6 +8,15 @@ #include +namespace cache { +enum class CacheVersion : int +{ + Older = -1, + Current = 0, + Newer = 1, +}; +} + struct RoomMember { QString user_id; diff --git a/src/Cache_p.h b/src/Cache_p.h index 982099ea..0d66a608 100644 --- a/src/Cache_p.h +++ b/src/Cache_p.h @@ -102,8 +102,9 @@ public: void removeRoom(const std::string &roomid); void setup(); - bool isFormatValid(); + cache::CacheVersion formatVersion(); void setCurrentFormat(); + bool runMigrations(); std::map roomMessages(); diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp index 981e6b80..689e9ca4 100644 --- a/src/ChatPage.cpp +++ b/src/ChatPage.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -642,20 +643,37 @@ ChatPage::bootstrap(QString userid, QString homeserver, QString token) &NotificationsManager::removeNotification); const bool isInitialized = cache::isInitialized(); - const bool isValid = cache::isFormatValid(); + const auto cacheVersion = cache::formatVersion(); if (!isInitialized) { cache::setCurrentFormat(); - } else if (isInitialized && !isValid) { - // TODO: Deleting session data but keep using the - // same device doesn't work. - cache::deleteData(); - - cache::init(userid); - cache::setCurrentFormat(); - } else if (isInitialized) { - loadStateFromCache(); - return; + } else { + if (cacheVersion == cache::CacheVersion::Current) { + loadStateFromCache(); + return; + } else if (cacheVersion == cache::CacheVersion::Older) { + if (!cache::runMigrations()) { + QMessageBox::critical( + this, + tr("Cache migration failed!"), + tr("Migrating the cache to the current version failed. " + "This can have different reasons. Please open an " + "issue and try to use an older version in the mean " + "time. Alternatively you can try deleting the cache " + "manually")); + QCoreApplication::quit(); + } + loadStateFromCache(); + return; + } else if (cacheVersion == cache::CacheVersion::Newer) { + QMessageBox::critical( + this, + tr("Incompatible cache version"), + tr("The cache on your disk is newer than this version of Nheko " + "supports. Please update or clear your cache.")); + QCoreApplication::quit(); + return; + } } } catch (const lmdb::error &e) { -- cgit 1.5.1 From d6685e8d61baf7ac90daffa7457422daead55426 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Sat, 2 May 2020 17:24:45 +0200 Subject: Add delete pending_receipts migration --- src/Cache.cpp | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/Cache.cpp b/src/Cache.cpp index 1a097cff..1ae7a846 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -36,7 +36,7 @@ //! Should be changed when a breaking change occurs in the cache format. //! This will reset client's data. -static const std::string CURRENT_CACHE_FORMAT_VERSION("2018.09.21"); +static const std::string CURRENT_CACHE_FORMAT_VERSION("2020.05.01"); static const std::string SECRET("secret"); static lmdb::val NEXT_BATCH_KEY("next_batch"); @@ -669,6 +669,47 @@ Cache::deleteData() bool Cache::runMigrations() { + auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY); + + lmdb::val current_version; + bool res = lmdb::dbi_get(txn, syncStateDb_, CACHE_FORMAT_VERSION_KEY, current_version); + + txn.commit(); + + if (!res) + return false; + + std::string stored_version(current_version.data(), current_version.size()); + + std::vector>> migrations{ + {"2020.05.01", + [this]() { + try { + auto txn = lmdb::txn::begin(env_, nullptr); + auto pending_receipts = + lmdb::dbi::open(txn, "pending_receipts", MDB_CREATE); + lmdb::dbi_drop(txn, pending_receipts, true); + txn.commit(); + } catch (const lmdb::error &) { + nhlog::db()->critical( + "Failed to delete pending_receipts database in migration!"); + return false; + } + + nhlog::db()->info("Successfully deleted pending receipts database."); + return true; + }}, + }; + + for (const auto &[target_version, migration] : migrations) { + if (target_version > stored_version) + if (!migration()) { + nhlog::db()->critical("migration failure!"); + return false; + } + } + + setCurrentFormat(); return true; } -- cgit 1.5.1