@@ -420,6 +420,10 @@ async def _compute_interested_rooms_new_tables(
420
420
Dict [str , RoomsForUserType ], filtered_sync_room_map
421
421
),
422
422
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 ),
423
427
)
424
428
425
429
for range in list_config .ranges :
@@ -462,7 +466,7 @@ async def _compute_interested_rooms_new_tables(
462
466
)
463
467
464
468
lists [list_key ] = SlidingSyncResult .SlidingWindowList (
465
- count = len (sorted_room_info ),
469
+ count = len (filtered_sync_room_map ),
466
470
ops = ops ,
467
471
)
468
472
@@ -1980,15 +1984,21 @@ async def sort_rooms(
1980
1984
self ,
1981
1985
sync_room_map : Dict [str , RoomsForUserType ],
1982
1986
to_token : StreamToken ,
1987
+ limit : Optional [int ] = None ,
1983
1988
) -> List [RoomsForUserType ]:
1984
1989
"""
1985
1990
Sort by `stream_ordering` of the last event that the user should see in the
1986
1991
room. `stream_ordering` is unique so we get a stable sort.
1987
1992
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
+
1988
1997
Args:
1989
1998
sync_room_map: Dictionary of room IDs to sort along with membership
1990
1999
information in the room at the time of `to_token`.
1991
2000
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.
1992
2002
1993
2003
Returns:
1994
2004
A sorted list of room IDs by `stream_ordering` along with membership information.
@@ -1998,8 +2008,23 @@ async def sort_rooms(
1998
2008
# user should see in the room (<= `to_token`)
1999
2009
last_activity_in_room_map : Dict [str , int ] = {}
2000
2010
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
+
2001
2019
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 :
2003
2028
# If the user has left/been invited/knocked/been banned from a
2004
2029
# room, they shouldn't see anything past that point.
2005
2030
#
@@ -2009,6 +2034,48 @@ async def sort_rooms(
2009
2034
# https://github.com/matrix-org/matrix-spec-proposals/pull/3575#discussion_r1653045932
2010
2035
last_activity_in_room_map [room_id ] = room_for_user .event_pos .stream
2011
2036
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
+
2012
2079
# For fully-joined rooms, we find the latest activity at/before the
2013
2080
# `to_token`.
2014
2081
joined_room_positions = (
0 commit comments