Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F7966442
D237.1759521628.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
7 KB
Referenced Files
None
Subscribers
None
D237.1759521628.diff
View Options
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
Details
Attached
Mime Type
text/plain
Expires
Fri, Oct 3, 1:00 PM (21 h, 21 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
491539
Default Alt Text
D237.1759521628.diff (7 KB)
Attached To
Mode
D237: Add purging event support
Attached
Detach File
Event Timeline
Log In to Comment