diff --git a/src/Cache.cpp b/src/Cache.cpp
index 0c692d07..0d879584 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -2304,6 +2304,11 @@ Cache::saveTimelineMessages(lmdb::txn &txn,
lmdb::val event_id = event_id_val;
+ json orderEntry = json::object();
+ orderEntry["event_id"] = event_id_val;
+ if (first && !res.prev_batch.empty())
+ orderEntry["prev_batch"] = res.prev_batch;
+
lmdb::val txn_order;
if (!txn_id.empty() &&
lmdb::dbi_get(txn, evToOrderDb, lmdb::val(txn_id), txn_order)) {
@@ -2317,7 +2322,7 @@ Cache::saveTimelineMessages(lmdb::txn &txn,
lmdb::dbi_del(txn, msg2orderDb, lmdb::val(txn_id));
}
- lmdb::dbi_put(txn, orderDb, txn_order, event_id);
+ lmdb::dbi_put(txn, orderDb, txn_order, lmdb::val(orderEntry.dump()));
lmdb::dbi_put(txn, evToOrderDb, event_id, txn_order);
lmdb::dbi_del(txn, evToOrderDb, lmdb::val(txn_id));
@@ -2389,10 +2394,6 @@ Cache::saveTimelineMessages(lmdb::txn &txn,
++index;
- json orderEntry = json::object();
- orderEntry["event_id"] = event_id_val;
- if (first && !res.prev_batch.empty())
- orderEntry["prev_batch"] = res.prev_batch;
first = false;
nhlog::db()->debug("saving '{}'", orderEntry.dump());
@@ -2440,6 +2441,7 @@ Cache::saveOldMessages(const std::string &room_id, const mtx::responses::Message
auto relationsDb = getRelationsDb(txn, room_id);
auto orderDb = getEventOrderDb(txn, room_id);
+ auto evToOrderDb = getEventToOrderDb(txn, room_id);
auto msg2orderDb = getMessageToOrderDb(txn, room_id);
auto order2msgDb = getOrderToMessageDb(txn, room_id);
@@ -2483,6 +2485,7 @@ Cache::saveOldMessages(const std::string &room_id, const mtx::responses::Message
lmdb::dbi_put(
txn, orderDb, lmdb::val(&index, sizeof(index)), lmdb::val(orderEntry.dump()));
+ lmdb::dbi_put(txn, evToOrderDb, event_id, lmdb::val(&index, sizeof(index)));
// TODO(Nico): Allow blacklisting more event types in UI
if (event["type"] != "m.reaction" && event["type"] != "m.dummy") {
@@ -2516,6 +2519,94 @@ Cache::saveOldMessages(const std::string &room_id, const mtx::responses::Message
return msgIndex;
}
+void
+Cache::clearTimeline(const std::string &room_id)
+{
+ auto txn = lmdb::txn::begin(env_);
+ auto eventsDb = getEventsDb(txn, room_id);
+ auto relationsDb = getRelationsDb(txn, room_id);
+
+ auto orderDb = getEventOrderDb(txn, room_id);
+ auto evToOrderDb = getEventToOrderDb(txn, room_id);
+ auto msg2orderDb = getMessageToOrderDb(txn, room_id);
+ auto order2msgDb = getOrderToMessageDb(txn, room_id);
+
+ lmdb::val indexVal, val;
+ auto cursor = lmdb::cursor::open(txn, orderDb);
+
+ bool start = true;
+ bool passed_pagination_token = false;
+ while (cursor.get(indexVal, val, start ? MDB_LAST : MDB_PREV)) {
+ start = false;
+ json obj;
+
+ try {
+ obj = json::parse(std::string_view(val.data(), val.size()));
+ } catch (std::exception &) {
+ // workaround bug in the initial db format, where we sometimes didn't store
+ // json...
+ obj = {{"event_id", std::string(val.data(), val.size())}};
+ }
+
+ if (passed_pagination_token) {
+ if (obj.count("event_id") != 0) {
+ lmdb::val event_id = obj["event_id"].get<std::string>();
+ lmdb::dbi_del(txn, evToOrderDb, event_id);
+ lmdb::dbi_del(txn, eventsDb, event_id);
+
+ lmdb::dbi_del(txn, relationsDb, event_id);
+
+ lmdb::val order{};
+ bool exists = lmdb::dbi_get(txn, msg2orderDb, event_id, order);
+ if (exists) {
+ lmdb::dbi_del(txn, order2msgDb, order);
+ lmdb::dbi_del(txn, msg2orderDb, event_id);
+ }
+ }
+ lmdb::cursor_del(cursor);
+ } else {
+ if (obj.count("prev_batch") != 0)
+ passed_pagination_token = true;
+ }
+ }
+
+ auto msgCursor = lmdb::cursor::open(txn, order2msgDb);
+ start = true;
+ while (msgCursor.get(indexVal, val, start ? MDB_LAST : MDB_PREV)) {
+ start = false;
+
+ lmdb::val eventId;
+ bool innerStart = true;
+ bool found = false;
+ while (cursor.get(indexVal, eventId, innerStart ? MDB_LAST : MDB_PREV)) {
+ innerStart = false;
+
+ json obj;
+ try {
+ obj = json::parse(std::string_view(eventId.data(), eventId.size()));
+ } catch (std::exception &) {
+ obj = {{"event_id", std::string(eventId.data(), eventId.size())}};
+ }
+
+ if (obj["event_id"] == std::string(val.data(), val.size())) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ break;
+ }
+
+ do {
+ lmdb::cursor_del(msgCursor);
+ } while (msgCursor.get(indexVal, val, MDB_PREV));
+
+ cursor.close();
+ msgCursor.close();
+ txn.commit();
+}
+
mtx::responses::Notifications
Cache::getTimelineMentionsForRoom(lmdb::txn &txn, const std::string &room_id)
{
@@ -2654,11 +2745,13 @@ Cache::deleteOldMessages()
auto room_ids = getRoomIds(txn);
for (const auto &room_id : room_ids) {
- auto orderDb = getEventOrderDb(txn, room_id);
- auto o2m = getOrderToMessageDb(txn, room_id);
- auto m2o = getMessageToOrderDb(txn, room_id);
- auto eventsDb = getEventsDb(txn, room_id);
- auto cursor = lmdb::cursor::open(txn, orderDb);
+ auto orderDb = getEventOrderDb(txn, room_id);
+ auto evToOrderDb = getEventToOrderDb(txn, room_id);
+ auto o2m = getOrderToMessageDb(txn, room_id);
+ auto m2o = getMessageToOrderDb(txn, room_id);
+ auto eventsDb = getEventsDb(txn, room_id);
+ auto relationsDb = getRelationsDb(txn, room_id);
+ auto cursor = lmdb::cursor::open(txn, orderDb);
uint64_t first, last;
if (cursor.get(indexVal, val, MDB_LAST)) {
@@ -2678,14 +2771,17 @@ Cache::deleteOldMessages()
bool start = true;
while (cursor.get(indexVal, val, start ? MDB_FIRST : MDB_NEXT) &&
- message_count-- < MAX_RESTORED_MESSAGES) {
+ message_count-- > MAX_RESTORED_MESSAGES) {
start = false;
auto obj = json::parse(std::string_view(val.data(), val.size()));
if (obj.count("event_id") != 0) {
lmdb::val event_id = obj["event_id"].get<std::string>();
+ lmdb::dbi_del(txn, evToOrderDb, event_id);
lmdb::dbi_del(txn, eventsDb, event_id);
+ lmdb::dbi_del(txn, relationsDb, event_id);
+
lmdb::val order{};
bool exists = lmdb::dbi_get(txn, m2o, event_id, order);
if (exists) {
|