From 345dca35444771267f51fe011c62e5d135695069 Mon Sep 17 00:00:00 2001 From: Konstantinos Sideris Date: Sat, 25 Aug 2018 21:08:43 +0300 Subject: [PATCH] Add method to delete old messages periodically fixes #413 --- src/Cache.cpp | 68 ++++++++++++++++++++++++++++++++++++++++++++++-- src/Cache.h | 6 +++++ src/ChatPage.cpp | 5 ++++ 3 files changed, 77 insertions(+), 2 deletions(-) diff --git a/src/Cache.cpp b/src/Cache.cpp index b12c8679..d67a2e90 100644 --- a/src/Cache.cpp +++ b/src/Cache.cpp @@ -41,6 +41,9 @@ static const lmdb::val CACHE_FORMAT_VERSION_KEY("cache_format_version"); constexpr size_t MAX_RESTORED_MESSAGES = 30; +constexpr auto DB_SIZE = 256UL * 1024UL * 1024UL; // 256 MB +constexpr auto MAX_DBS = 1024UL; + //! Cache databases and their format. //! //! Contains UI information for the joined rooms. (i.e name, topic, avatar url etc). @@ -134,8 +137,8 @@ Cache::setup() bool isInitial = !QFile::exists(statePath); env_ = lmdb::env::create(); - env_.set_mapsize(256UL * 1024UL * 1024UL); /* 256 MB */ - env_.set_max_dbs(1024UL); + env_.set_mapsize(DB_SIZE); + env_.set_max_dbs(MAX_DBS); if (isInitial) { nhlog::db()->info("initializing LMDB"); @@ -1786,6 +1789,67 @@ Cache::isNotificationSent(const std::string &event_id) return res; } +std::vector +Cache::getRoomIds(lmdb::txn &txn) +{ + auto db = lmdb::dbi::open(txn, ROOMS_DB, MDB_CREATE); + auto cursor = lmdb::cursor::open(txn, db); + + std::vector rooms; + + std::string room_id, _unused; + while (cursor.get(room_id, _unused, MDB_NEXT)) + rooms.emplace_back(room_id); + + cursor.close(); + + return rooms; +} + +void +Cache::deleteOldMessages() +{ + auto txn = lmdb::txn::begin(env_); + auto room_ids = getRoomIds(txn); + + for (const auto &id : room_ids) { + auto msg_db = getMessagesDb(txn, id); + + std::string ts, event; + uint64_t idx = 0; + + const auto db_size = msg_db.size(txn); + if (db_size <= 3 * MAX_RESTORED_MESSAGES) + continue; + + nhlog::db()->info("[{}] message count: {}", id, db_size); + + auto cursor = lmdb::cursor::open(txn, msg_db); + while (cursor.get(ts, event, MDB_NEXT)) { + idx += 1; + + if (idx > MAX_RESTORED_MESSAGES) + lmdb::cursor_del(cursor); + } + + cursor.close(); + + nhlog::db()->info("[{}] updated message count: {}", id, msg_db.size(txn)); + } + + txn.commit(); +} + +void +Cache::deleteOldData() noexcept +{ + try { + deleteOldMessages(); + } catch (const lmdb::error &e) { + nhlog::db()->error("failed to delete old messages: {}", e.what()); + } +} + bool Cache::hasEnoughPowerLevel(const std::vector &eventTypes, const std::string &room_id, diff --git a/src/Cache.h b/src/Cache.h index beca502f..c2f8cfc8 100644 --- a/src/Cache.h +++ b/src/Cache.h @@ -388,6 +388,12 @@ public: //! Check if we have sent a desktop notification for the given event id. bool isNotificationSent(const std::string &event_id); + //! Remove old unused data. + void deleteOldMessages(); + void deleteOldData() noexcept; + //! Retrieve all saved room ids. + std::vector getRoomIds(lmdb::txn &txn); + //! Mark a room that uses e2e encryption. void setEncryptedRoom(lmdb::txn &txn, const std::string &room_id); bool isRoomEncrypted(const std::string &room_id); diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp index 9f408a73..250d106d 100644 --- a/src/ChatPage.cpp +++ b/src/ChatPage.cpp @@ -1070,6 +1070,11 @@ ChatPage::trySync() emit syncTopBar(updates); emit syncRoomlist(updates); + + cache::client()->deleteOldData(); + } catch (const lmdb::map_full_error &e) { + nhlog::db()->error("lmdb is full: {}", e.what()); + cache::client()->deleteOldData(); } catch (const lmdb::error &e) { nhlog::db()->error("saving sync response: {}", e.what()); }