Page MenuHomePhorge

D237.1759522946.diff
No OneTemporary

Size
7 KB
Referenced Files
None
Subscribers
None

D237.1759522946.diff

diff --git a/src/client/actions/storage.hpp b/src/client/actions/storage.hpp
--- a/src/client/actions/storage.hpp
+++ b/src/client/actions/storage.hpp
@@ -11,4 +11,5 @@
namespace Kazv
{
[[nodiscard]] ClientResult updateClient(ClientModel m, LoadEventsFromStorageAction a);
+ [[nodiscard]] ClientResult updateClient(ClientModel m, PurgeRoomTimelineAction a);
}
diff --git a/src/client/actions/storage.cpp b/src/client/actions/storage.cpp
--- a/src/client/actions/storage.cpp
+++ b/src/client/actions/storage.cpp
@@ -41,4 +41,13 @@
return { m, lager::noop };
}
+
+ ClientResult updateClient(ClientModel m, PurgeRoomTimelineAction a)
+ {
+ m.roomList = RoomListModel::update(
+ std::move(m.roomList),
+ UpdateRoomAction{a.roomId, PurgeEventsAction{a.maxToKeep}}
+ );
+ return { m, lager::noop };
+ }
}
diff --git a/src/client/client-model.hpp b/src/client/client-model.hpp
--- a/src/client/client-model.hpp
+++ b/src/client/client-model.hpp
@@ -594,6 +594,14 @@
immer::map<std::string, EventList> relatedEvents;
};
+ /// Remove events from the model, keeping only the latest `maxToKeep` events.
+ /// This takes O(maxToKeep * log(maxToKeep)) time.
+ struct PurgeRoomTimelineAction
+ {
+ std::string roomId;
+ std::size_t maxToKeep;
+ };
+
template<class Archive>
void serialize(Archive &ar, ClientModel &m, std::uint32_t const version)
{
diff --git a/src/client/client.hpp b/src/client/client.hpp
--- a/src/client/client.hpp
+++ b/src/client/client.hpp
@@ -603,6 +603,19 @@
*/
BaseJob getRoomIdByAliasJob(std::string roomAlias) const;
+ /**
+ * Purge events in room, keeping the latest `numToKeep` events.
+ *
+ * The events are removed from the lager store. The timeline will
+ * contain at most `numToKeep` events, but the `messages` property
+ * may contain more in order to maintain the room invariants.
+ * @sa RoomModel
+ *
+ * @param roomId The id of the room to purge.
+ * @param numToKeep The number of events to keep.
+ */
+ PromiseT purgeRoomEvents(std::string roomId, std::size_t numToKeep) const;
+
private:
void syncForever(std::optional<int> retryTime = std::nullopt) const;
diff --git a/src/client/client.cpp b/src/client/client.cpp
--- a/src/client/client.cpp
+++ b/src/client/client.cpp
@@ -500,4 +500,9 @@
{
return Kazv::getRoomIdByAliasJob(clientCursor().get(), roomAlias);
}
+
+ auto Client::purgeRoomEvents(std::string roomId, std::size_t numToKeep) const -> PromiseT
+ {
+ return m_ctx.dispatch(PurgeRoomTimelineAction{roomId, numToKeep});
+ }
}
diff --git a/src/client/clientfwd.hpp b/src/client/clientfwd.hpp
--- a/src/client/clientfwd.hpp
+++ b/src/client/clientfwd.hpp
@@ -79,6 +79,7 @@
struct ResubmitJobAction;
struct LoadEventsFromStorageAction;
+ struct PurgeRoomTimelineAction;
struct ClientModel;
@@ -145,7 +146,8 @@
ResubmitJobAction,
- LoadEventsFromStorageAction
+ LoadEventsFromStorageAction,
+ PurgeRoomTimelineAction
>;
using ClientEffect = Effect<ClientAction, lager::deps<>>;
diff --git a/src/client/room/room-model.hpp b/src/client/room/room-model.hpp
--- a/src/client/room/room-model.hpp
+++ b/src/client/room/room-model.hpp
@@ -226,6 +226,16 @@
*/
auto sortKeyForTimelineEvent(Event e) -> std::tuple<Timestamp, std::string>;
+ /**
+ * The model to store information about a room.
+ *
+ * Room invariants:
+ * Any event in timeline is in messages.
+ * Any event in undecryptedEvents is in messages.
+ * Any event in unreadNotificationEventIds is in messages.
+ * Any relater (i.e. child) event in reverseEventRelationships is in messages.
+ * localReadMarker (if not empty) is in messages.
+ */
struct RoomModel
{
using Membership = RoomMembership;
@@ -341,6 +351,12 @@
void recalculateUndecryptedEvents();
+ /**
+ * Check if the invariants in the model are satisfied.
+ * @return true iff the invariants are satisfied.
+ */
+ bool checkInvariants() const;
+
using Action = std::variant<
AddStateEventsAction,
MaybeAddStateEventsAction,
@@ -362,7 +378,8 @@
UpdateInvitedMemberCountAction,
AddLocalNotificationsAction,
RemoveReadLocalNotificationsAction,
- UpdateLocalReadMarkerAction
+ UpdateLocalReadMarkerAction,
+ PurgeEventsAction
>;
static RoomModel update(RoomModel r, Action a);
diff --git a/src/client/room/room-model.cpp b/src/client/room/room-model.cpp
--- a/src/client/room/room-model.cpp
+++ b/src/client/room/room-model.cpp
@@ -417,6 +417,39 @@
r.localReadMarker = a.localReadMarker;
auto next = RoomModel::update(std::move(r), RemoveReadLocalNotificationsAction{a.myUserId});
return next;
+ },
+ [&](PurgeEventsAction a) {
+ auto numToDrop = r.timeline.size() - a.maxToKeep;
+ if (numToDrop <= 0) {
+ return r;
+ }
+ auto keepEvents = intoImmer(
+ EventList{},
+ zug::map([&r](const auto &eventId) {
+ return r.messages[eventId];
+ }),
+ std::move(r.timeline).drop(numToDrop)
+ );
+ auto origMessages = r.messages;
+ r.reverseEventRelationships = {};
+ r.timeline = {};
+ r.messages = {};
+ r.undecryptedEvents = {};
+
+ auto next = update(std::move(r), AddMessagesAction{intoImmer(
+ EventList{},
+ zug::map([&origMessages](const auto &eventId) {
+ return origMessages[eventId];
+ }),
+ r.unreadNotificationEventIds
+ )});
+
+ return update(std::move(next), AddToTimelineAction{
+ keepEvents,
+ std::nullopt,
+ std::nullopt,
+ std::nullopt,
+ });
}
);
}
@@ -709,4 +742,24 @@
return kv.second;
}), messages));
}
+
+ bool RoomModel::checkInvariants() const
+ {
+ auto inMessages = [this](const std::string &eventId) {
+ return !!messages.count(eventId);
+ };
+ return immer::all_of(timeline, inMessages)
+ && immer::all_of(unreadNotificationEventIds, inMessages)
+ && std::all_of(undecryptedEvents.begin(), undecryptedEvents.end(), [&inMessages](const auto &p) {
+ return immer::all_of(p.second, inMessages);
+ })
+ && (localReadMarker.empty() || messages.count(localReadMarker))
+ && std::all_of(reverseEventRelationships.begin(), reverseEventRelationships.end(), [&inMessages](const auto &p) {
+ const auto &relTypeToEventsMap = p.second;
+ return std::all_of(relTypeToEventsMap.begin(), relTypeToEventsMap.end(), [&inMessages](const auto &p2) {
+ const auto &events = p2.second;
+ return immer::all_of(events, inMessages);
+ });
+ });
+ }
}

File Metadata

Mime Type
text/plain
Expires
Fri, Oct 3, 1:22 PM (21 h, 42 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
491539
Default Alt Text
D237.1759522946.diff (7 KB)

Event Timeline