diff --git a/synapse/handlers/sliding_sync/__init__.py b/synapse/handlers/sliding_sync/__init__.py index 17a2f511bd..fabc01812c 100644 --- a/synapse/handlers/sliding_sync/__init__.py +++ b/synapse/handlers/sliding_sync/__init__.py @@ -17,6 +17,7 @@ import logging from itertools import chain from typing import ( TYPE_CHECKING, + AbstractSet, Any, Dict, List, @@ -332,6 +333,7 @@ class SlidingSyncHandler: sync_config, from_token ) ) + new_connection_state = previous_connection_state.get_mutable() # Get all of the room IDs that the user should be able to see in the sync # response @@ -349,6 +351,10 @@ class SlidingSyncHandler: ) ) + lists_to_rooms: Mapping[str, AbstractSet[str]] = {} + if previous_connection_state is not None: + lists_to_rooms = previous_connection_state.list_to_rooms + # Assemble sliding window lists lists: Dict[str, SlidingSyncResult.SlidingWindowList] = {} # Keep track of the rooms that we can display and need to fetch more info about @@ -365,35 +371,46 @@ class SlidingSyncHandler: for list_key, list_config in sync_config.lists.items(): # Apply filters - filtered_sync_room_map = sync_room_map - if list_config.filters is not None: - filtered_sync_room_map = await self.filter_rooms( - sync_config.user, - sync_room_map, - list_config.filters, - to_token, + previous_found_rooms = lists_to_rooms.get(list_key) + if previous_found_rooms: + filtered_sync_room_map = { + room_id: sync_room_map[room_id] + for room_id in previous_found_rooms + } + else: + filtered_sync_room_map = sync_room_map + if list_config.filters is not None: + filtered_sync_room_map = await self.filter_rooms( + sync_config.user, + sync_room_map, + list_config.filters, + to_token, + ) + + # Find which rooms are partially stated and may need to be filtered out + # depending on the `required_state` requested (see below). + partial_state_room_map = ( + await self.store.is_partial_state_room_batched( + filtered_sync_room_map.keys() + ) ) - # Find which rooms are partially stated and may need to be filtered out - # depending on the `required_state` requested (see below). - partial_state_room_map = ( - await self.store.is_partial_state_room_batched( + # Since creating the `RoomSyncConfig` takes some work, let's just do it + # once and make a copy whenever we need it. + room_sync_config = RoomSyncConfig.from_room_config(list_config) + + # Exclude partially-stated rooms if we must wait for the room to be + # fully-stated + if room_sync_config.must_await_full_state(self.is_mine_id): + filtered_sync_room_map = { + room_id: room + for room_id, room in filtered_sync_room_map.items() + if not partial_state_room_map.get(room_id) + } + + new_connection_state.list_to_rooms[list_key] = set( filtered_sync_room_map.keys() ) - ) - - # Since creating the `RoomSyncConfig` takes some work, let's just do it - # once and make a copy whenever we need it. - room_sync_config = RoomSyncConfig.from_room_config(list_config) - - # Exclude partially-stated rooms if we must wait for the room to be - # fully-stated - if room_sync_config.must_await_full_state(self.is_mine_id): - filtered_sync_room_map = { - room_id: room - for room_id, room in filtered_sync_room_map.items() - if not partial_state_room_map.get(room_id) - } all_rooms.update(filtered_sync_room_map) @@ -564,8 +581,6 @@ class SlidingSyncHandler: if room_id in rooms_should_send } - new_connection_state = previous_connection_state.get_mutable() - @trace @tag_args async def handle_room(room_id: str) -> None: diff --git a/synapse/storage/databases/main/sliding_sync.py b/synapse/storage/databases/main/sliding_sync.py index 2166758a4c..d270bd8445 100644 --- a/synapse/storage/databases/main/sliding_sync.py +++ b/synapse/storage/databases/main/sliding_sync.py @@ -13,7 +13,7 @@ # -from typing import TYPE_CHECKING, Dict, List, Mapping, Optional, Set, cast +from typing import TYPE_CHECKING, AbstractSet, Dict, List, Mapping, Optional, Set, cast import attr @@ -378,6 +378,7 @@ class SlidingSyncStore(SQLBaseStore): rooms=RoomStatusMap(rooms), receipts=RoomStatusMap(receipts), room_configs=room_configs, + list_to_rooms={}, ) @@ -396,6 +397,7 @@ class PerConnectionStateDB: receipts: "RoomStatusMap[str]" room_configs: Mapping[str, "RoomSyncConfig"] + list_to_rooms: Mapping[str, AbstractSet[str]] @staticmethod async def from_state( @@ -438,6 +440,7 @@ class PerConnectionStateDB: rooms=RoomStatusMap(rooms), receipts=RoomStatusMap(receipts), room_configs=per_connection_state.room_configs.maps[0], + list_to_rooms=per_connection_state.list_to_rooms.maps[0], ) async def to_state(self, store: "DataStore") -> "PerConnectionState": @@ -470,4 +473,5 @@ class PerConnectionStateDB: rooms=RoomStatusMap(rooms), receipts=RoomStatusMap(receipts), room_configs=self.room_configs, + list_to_rooms=self.list_to_rooms, ) diff --git a/synapse/types/handlers/sliding_sync.py b/synapse/types/handlers/sliding_sync.py index a2b963db93..6370247193 100644 --- a/synapse/types/handlers/sliding_sync.py +++ b/synapse/types/handlers/sliding_sync.py @@ -828,14 +828,18 @@ class PerConnectionState: room_configs: Mapping[str, RoomSyncConfig] = attr.Factory(dict) + list_to_rooms: Mapping[str, AbstractSet[str]] = attr.Factory(dict) + def get_mutable(self) -> "MutablePerConnectionState": """Get a mutable copy of this state.""" room_configs = cast(MutableMapping[str, RoomSyncConfig], self.room_configs) + list_to_rooms = cast(MutableMapping[str, Set[str]], self.list_to_rooms) return MutablePerConnectionState( rooms=self.rooms.get_mutable(), receipts=self.receipts.get_mutable(), room_configs=ChainMap({}, room_configs), + list_to_rooms=ChainMap({}, list_to_rooms), ) def copy(self) -> "PerConnectionState": @@ -843,10 +847,16 @@ class PerConnectionState: rooms=self.rooms.copy(), receipts=self.receipts.copy(), room_configs=dict(self.room_configs), + list_to_rooms=dict(self.list_to_rooms), ) def __len__(self) -> int: - return len(self.rooms) + len(self.receipts) + len(self.room_configs) + return ( + len(self.rooms) + + len(self.receipts) + + len(self.room_configs) + + len(self.list_to_rooms) + ) @attr.s(auto_attribs=True) @@ -858,13 +868,20 @@ class MutablePerConnectionState(PerConnectionState): room_configs: typing.ChainMap[str, RoomSyncConfig] + list_to_rooms: typing.ChainMap[str, Set[str]] + def has_updates(self) -> bool: return ( bool(self.rooms.get_updates()) or bool(self.receipts.get_updates()) or bool(self.get_room_config_updates()) + or bool(self.list_to_rooms.maps[0]) ) def get_room_config_updates(self) -> Mapping[str, RoomSyncConfig]: """Get updates to the room sync config""" return self.room_configs.maps[0] + + def get_list_to_rooms_updates(self) -> Mapping[str, StrCollection]: + """Get updates to the `list_to_rooms`""" + return self.list_to_rooms.maps[0]