Skip to content

Commit 75e2c17

Browse files
erikjohnstondevonh
andauthored
Speed up sorting of sliding sync rooms in initial request (#17734)
We do this by using the event stream cache. --------- Co-authored-by: Devon Hudson <devon.dmytro@gmail.com>
1 parent a851f6b commit 75e2c17

File tree

2 files changed

+70
-2
lines changed

2 files changed

+70
-2
lines changed

changelog.d/17734.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Minor speed up of initial sliding sync requests.

synapse/handlers/sliding_sync/room_lists.py

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,10 @@ async def _compute_interested_rooms_new_tables(
420420
Dict[str, RoomsForUserType], filtered_sync_room_map
421421
),
422422
to_token,
423+
# We only need to sort the rooms up to the end
424+
# of the largest range. Both sides of range are
425+
# inclusive so we `+ 1`.
426+
limit=max(range[1] + 1 for range in list_config.ranges),
423427
)
424428

425429
for range in list_config.ranges:
@@ -462,7 +466,7 @@ async def _compute_interested_rooms_new_tables(
462466
)
463467

464468
lists[list_key] = SlidingSyncResult.SlidingWindowList(
465-
count=len(sorted_room_info),
469+
count=len(filtered_sync_room_map),
466470
ops=ops,
467471
)
468472

@@ -1980,15 +1984,21 @@ async def sort_rooms(
19801984
self,
19811985
sync_room_map: Dict[str, RoomsForUserType],
19821986
to_token: StreamToken,
1987+
limit: Optional[int] = None,
19831988
) -> List[RoomsForUserType]:
19841989
"""
19851990
Sort by `stream_ordering` of the last event that the user should see in the
19861991
room. `stream_ordering` is unique so we get a stable sort.
19871992
1993+
If `limit` is specified then sort may return fewer entries, but will
1994+
always return at least the top N rooms. This is useful as we don't always
1995+
need to sort the full list, but are just interested in the top N.
1996+
19881997
Args:
19891998
sync_room_map: Dictionary of room IDs to sort along with membership
19901999
information in the room at the time of `to_token`.
19912000
to_token: We sort based on the events in the room at this token (<= `to_token`)
2001+
limit: The number of rooms that we need to return from the top of the list.
19922002
19932003
Returns:
19942004
A sorted list of room IDs by `stream_ordering` along with membership information.
@@ -1998,8 +2008,23 @@ async def sort_rooms(
19982008
# user should see in the room (<= `to_token`)
19992009
last_activity_in_room_map: Dict[str, int] = {}
20002010

2011+
# Same as above, except for positions that we know are in the event
2012+
# stream cache.
2013+
cached_positions: Dict[str, int] = {}
2014+
2015+
earliest_cache_position = (
2016+
self.store._events_stream_cache.get_earliest_known_position()
2017+
)
2018+
20012019
for room_id, room_for_user in sync_room_map.items():
2002-
if room_for_user.membership != Membership.JOIN:
2020+
if room_for_user.membership == Membership.JOIN:
2021+
# For joined rooms check the stream change cache.
2022+
cached_position = (
2023+
self.store._events_stream_cache.get_max_pos_of_last_change(room_id)
2024+
)
2025+
if cached_position is not None:
2026+
cached_positions[room_id] = cached_position
2027+
else:
20032028
# If the user has left/been invited/knocked/been banned from a
20042029
# room, they shouldn't see anything past that point.
20052030
#
@@ -2009,6 +2034,48 @@ async def sort_rooms(
20092034
# https://github.com/matrix-org/matrix-spec-proposals/pull/3575#discussion_r1653045932
20102035
last_activity_in_room_map[room_id] = room_for_user.event_pos.stream
20112036

2037+
# If the stream position is in range of the stream change cache
2038+
# we can include it.
2039+
if room_for_user.event_pos.stream > earliest_cache_position:
2040+
cached_positions[room_id] = room_for_user.event_pos.stream
2041+
2042+
# If we are only asked for the top N rooms, and we have enough from
2043+
# looking in the stream change cache, then we can return early. This
2044+
# is because the cache must include all entries above
2045+
# `.get_earliest_known_position()`.
2046+
if limit is not None and len(cached_positions) >= limit:
2047+
# ... but first we need to handle the case where the cached max
2048+
# position is greater than the to_token, in which case we do
2049+
# actually query the DB. This should happen rarely, so can do it in
2050+
# a loop.
2051+
for room_id, position in list(cached_positions.items()):
2052+
if position > to_token.room_key.stream:
2053+
result = await self.store.get_last_event_pos_in_room_before_stream_ordering(
2054+
room_id, to_token.room_key
2055+
)
2056+
if (
2057+
result is not None
2058+
and result[1].stream > earliest_cache_position
2059+
):
2060+
# We have a stream position in the cached range.
2061+
cached_positions[room_id] = result[1].stream
2062+
else:
2063+
# No position in the range, so we remove the entry.
2064+
cached_positions.pop(room_id)
2065+
2066+
if limit is not None and len(cached_positions) >= limit:
2067+
return sorted(
2068+
(
2069+
room
2070+
for room in sync_room_map.values()
2071+
if room.room_id in cached_positions
2072+
),
2073+
# Sort by the last activity (stream_ordering) in the room
2074+
key=lambda room_info: cached_positions[room_info.room_id],
2075+
# We want descending order
2076+
reverse=True,
2077+
)
2078+
20122079
# For fully-joined rooms, we find the latest activity at/before the
20132080
# `to_token`.
20142081
joined_room_positions = (

0 commit comments

Comments
 (0)