From 99926affef9578bdb23f0d9911eafe98c3b75c2e Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 22 Sep 2022 11:46:57 +0100 Subject: [PATCH] Sync hot-path optimisation for `filter_events_for_client` Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- synapse/handlers/sync.py | 2 ++ synapse/visibility.py | 15 ++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/synapse/handlers/sync.py b/synapse/handlers/sync.py index 5293fa4d0e..bb348db3b9 100644 --- a/synapse/handlers/sync.py +++ b/synapse/handlers/sync.py @@ -539,6 +539,7 @@ class SyncHandler: sync_config.user.to_string(), recents, always_include_ids=current_state_ids, + limit=timeline_limit + 1, ) log_kv({"recents_after_visibility_filtering": len(recents)}) else: @@ -616,6 +617,7 @@ class SyncHandler: sync_config.user.to_string(), loaded_recents, always_include_ids=current_state_ids, + limit=timeline_limit + 1 - len(recents), ) log_kv({"loaded_recents_after_client_filtering": len(loaded_recents)}) diff --git a/synapse/visibility.py b/synapse/visibility.py index c810a05907..733b0a7027 100644 --- a/synapse/visibility.py +++ b/synapse/visibility.py @@ -60,6 +60,7 @@ async def filter_events_for_client( is_peeking: bool = False, always_include_ids: FrozenSet[str] = frozenset(), filter_send_to_client: bool = True, + limit: int = -1, ) -> List[EventBase]: """ Check which events a user is allowed to see. If the user can see the event but its @@ -78,6 +79,7 @@ async def filter_events_for_client( filter_send_to_client: Whether we're checking an event that's going to be sent to a client. This might not always be the case since this function can also be called to check whether a user can see the state at a given point. + limit: The number of events to bail at, as a hot path optimisation. Returns: The filtered events. @@ -122,12 +124,15 @@ async def filter_events_for_client( sender_erased=erased_senders.get(event.sender, False), ) - # Check each event: gives an iterable of None or (a potentially modified) - # EventBase. - filtered_events = map(allowed, events) + filtered_events: List[EventBase] = [] + for event in events: + checked = allowed(event) + if checked is not None: + filtered_events.append(checked) + if len(filtered_events) >= limit >= 0: + break - # Turn it into a list and remove None entries before returning. - return [ev for ev in filtered_events if ev] + return filtered_events async def filter_event_for_clients_with_state(