mirror of
https://git.anonymousland.org/anonymousland/synapse.git
synced 2024-12-18 11:54:21 -05:00
Skip unused calculations in sync handler. (#14908)
If a sync request does not need to calculate per-room entries & is not generating presence & is not generating device list data (e.g. during initial sync) avoid the expensive calculation of room specific data. This is a micro-optimisation for clients syncing simply to receive to-device information.
This commit is contained in:
parent
f36da501be
commit
da05b70af5
1
changelog.d/14908.misc
Normal file
1
changelog.d/14908.misc
Normal file
@ -0,0 +1 @@
|
|||||||
|
Improve performance of `/sync` in a few situations.
|
@ -283,6 +283,9 @@ class FilterCollection:
|
|||||||
await self._room_filter.filter(events)
|
await self._room_filter.filter(events)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def blocks_all_rooms(self) -> bool:
|
||||||
|
return self._room_filter.filters_all_rooms()
|
||||||
|
|
||||||
def blocks_all_presence(self) -> bool:
|
def blocks_all_presence(self) -> bool:
|
||||||
return (
|
return (
|
||||||
self._presence_filter.filters_all_types()
|
self._presence_filter.filters_all_types()
|
||||||
|
@ -1448,41 +1448,67 @@ class SyncHandler:
|
|||||||
sync_result_builder
|
sync_result_builder
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.debug("Fetching room data")
|
|
||||||
|
|
||||||
(
|
|
||||||
newly_joined_rooms,
|
|
||||||
newly_joined_or_invited_or_knocked_users,
|
|
||||||
newly_left_rooms,
|
|
||||||
newly_left_users,
|
|
||||||
) = await self._generate_sync_entry_for_rooms(
|
|
||||||
sync_result_builder, account_data_by_room
|
|
||||||
)
|
|
||||||
|
|
||||||
# Presence data is included if the server has it enabled and not filtered out.
|
# Presence data is included if the server has it enabled and not filtered out.
|
||||||
include_presence_data = (
|
include_presence_data = bool(
|
||||||
self.hs_config.server.use_presence
|
self.hs_config.server.use_presence
|
||||||
and not sync_config.filter_collection.blocks_all_presence()
|
and not sync_config.filter_collection.blocks_all_presence()
|
||||||
)
|
)
|
||||||
if include_presence_data:
|
# Device list updates are sent if a since token is provided.
|
||||||
logger.debug("Fetching presence data")
|
include_device_list_updates = bool(since_token and since_token.device_list_key)
|
||||||
await self._generate_sync_entry_for_presence(
|
|
||||||
sync_result_builder,
|
# If we do not care about the rooms or things which depend on the room
|
||||||
|
# data (namely presence and device list updates), then we can skip
|
||||||
|
# this process completely.
|
||||||
|
device_lists = DeviceListUpdates()
|
||||||
|
if (
|
||||||
|
not sync_result_builder.sync_config.filter_collection.blocks_all_rooms()
|
||||||
|
or include_presence_data
|
||||||
|
or include_device_list_updates
|
||||||
|
):
|
||||||
|
logger.debug("Fetching room data")
|
||||||
|
|
||||||
|
# Note that _generate_sync_entry_for_rooms sets sync_result_builder.joined, which
|
||||||
|
# is used in calculate_user_changes below.
|
||||||
|
(
|
||||||
newly_joined_rooms,
|
newly_joined_rooms,
|
||||||
newly_joined_or_invited_or_knocked_users,
|
newly_left_rooms,
|
||||||
|
) = await self._generate_sync_entry_for_rooms(
|
||||||
|
sync_result_builder, account_data_by_room
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Work out which users have joined or left rooms we're in. We use this
|
||||||
|
# to build the presence and device_list parts of the sync response in
|
||||||
|
# `_generate_sync_entry_for_presence` and
|
||||||
|
# `_generate_sync_entry_for_device_list` respectively.
|
||||||
|
if include_presence_data or include_device_list_updates:
|
||||||
|
# This uses the sync_result_builder.joined which is set in
|
||||||
|
# `_generate_sync_entry_for_rooms`, if that didn't find any joined
|
||||||
|
# rooms for some reason it is a no-op.
|
||||||
|
(
|
||||||
|
newly_joined_or_invited_or_knocked_users,
|
||||||
|
newly_left_users,
|
||||||
|
) = sync_result_builder.calculate_user_changes()
|
||||||
|
|
||||||
|
if include_presence_data:
|
||||||
|
logger.debug("Fetching presence data")
|
||||||
|
await self._generate_sync_entry_for_presence(
|
||||||
|
sync_result_builder,
|
||||||
|
newly_joined_rooms,
|
||||||
|
newly_joined_or_invited_or_knocked_users,
|
||||||
|
)
|
||||||
|
|
||||||
|
if include_device_list_updates:
|
||||||
|
device_lists = await self._generate_sync_entry_for_device_list(
|
||||||
|
sync_result_builder,
|
||||||
|
newly_joined_rooms=newly_joined_rooms,
|
||||||
|
newly_joined_or_invited_or_knocked_users=newly_joined_or_invited_or_knocked_users,
|
||||||
|
newly_left_rooms=newly_left_rooms,
|
||||||
|
newly_left_users=newly_left_users,
|
||||||
|
)
|
||||||
|
|
||||||
logger.debug("Fetching to-device data")
|
logger.debug("Fetching to-device data")
|
||||||
await self._generate_sync_entry_for_to_device(sync_result_builder)
|
await self._generate_sync_entry_for_to_device(sync_result_builder)
|
||||||
|
|
||||||
device_lists = await self._generate_sync_entry_for_device_list(
|
|
||||||
sync_result_builder,
|
|
||||||
newly_joined_rooms=newly_joined_rooms,
|
|
||||||
newly_joined_or_invited_or_knocked_users=newly_joined_or_invited_or_knocked_users,
|
|
||||||
newly_left_rooms=newly_left_rooms,
|
|
||||||
newly_left_users=newly_left_users,
|
|
||||||
)
|
|
||||||
|
|
||||||
logger.debug("Fetching OTK data")
|
logger.debug("Fetching OTK data")
|
||||||
device_id = sync_config.device_id
|
device_id = sync_config.device_id
|
||||||
one_time_keys_count: JsonDict = {}
|
one_time_keys_count: JsonDict = {}
|
||||||
@ -1551,6 +1577,7 @@ class SyncHandler:
|
|||||||
|
|
||||||
user_id = sync_result_builder.sync_config.user.to_string()
|
user_id = sync_result_builder.sync_config.user.to_string()
|
||||||
since_token = sync_result_builder.since_token
|
since_token = sync_result_builder.since_token
|
||||||
|
assert since_token is not None
|
||||||
|
|
||||||
# Take a copy since these fields will be mutated later.
|
# Take a copy since these fields will be mutated later.
|
||||||
newly_joined_or_invited_or_knocked_users = set(
|
newly_joined_or_invited_or_knocked_users = set(
|
||||||
@ -1558,92 +1585,85 @@ class SyncHandler:
|
|||||||
)
|
)
|
||||||
newly_left_users = set(newly_left_users)
|
newly_left_users = set(newly_left_users)
|
||||||
|
|
||||||
if since_token and since_token.device_list_key:
|
# We want to figure out what user IDs the client should refetch
|
||||||
# We want to figure out what user IDs the client should refetch
|
# device keys for, and which users we aren't going to track changes
|
||||||
# device keys for, and which users we aren't going to track changes
|
# for anymore.
|
||||||
# for anymore.
|
#
|
||||||
#
|
# For the first step we check:
|
||||||
# For the first step we check:
|
# a. if any users we share a room with have updated their devices,
|
||||||
# a. if any users we share a room with have updated their devices,
|
# and
|
||||||
# and
|
# b. we also check if we've joined any new rooms, or if a user has
|
||||||
# b. we also check if we've joined any new rooms, or if a user has
|
# joined a room we're in.
|
||||||
# joined a room we're in.
|
#
|
||||||
#
|
# For the second step we just find any users we no longer share a
|
||||||
# For the second step we just find any users we no longer share a
|
# room with by looking at all users that have left a room plus users
|
||||||
# room with by looking at all users that have left a room plus users
|
# that were in a room we've left.
|
||||||
# that were in a room we've left.
|
|
||||||
|
|
||||||
users_that_have_changed = set()
|
users_that_have_changed = set()
|
||||||
|
|
||||||
joined_rooms = sync_result_builder.joined_room_ids
|
joined_rooms = sync_result_builder.joined_room_ids
|
||||||
|
|
||||||
# Step 1a, check for changes in devices of users we share a room
|
# Step 1a, check for changes in devices of users we share a room
|
||||||
# with
|
# with
|
||||||
#
|
#
|
||||||
# We do this in two different ways depending on what we have cached.
|
# We do this in two different ways depending on what we have cached.
|
||||||
# If we already have a list of all the user that have changed since
|
# If we already have a list of all the user that have changed since
|
||||||
# the last sync then it's likely more efficient to compare the rooms
|
# the last sync then it's likely more efficient to compare the rooms
|
||||||
# they're in with the rooms the syncing user is in.
|
# they're in with the rooms the syncing user is in.
|
||||||
#
|
#
|
||||||
# If we don't have that info cached then we get all the users that
|
# If we don't have that info cached then we get all the users that
|
||||||
# share a room with our user and check if those users have changed.
|
# share a room with our user and check if those users have changed.
|
||||||
cache_result = self.store.get_cached_device_list_changes(
|
cache_result = self.store.get_cached_device_list_changes(
|
||||||
since_token.device_list_key
|
since_token.device_list_key
|
||||||
)
|
)
|
||||||
if cache_result.hit:
|
if cache_result.hit:
|
||||||
changed_users = cache_result.entities
|
changed_users = cache_result.entities
|
||||||
|
|
||||||
result = await self.store.get_rooms_for_users(changed_users)
|
result = await self.store.get_rooms_for_users(changed_users)
|
||||||
|
|
||||||
for changed_user_id, entries in result.items():
|
for changed_user_id, entries in result.items():
|
||||||
# Check if the changed user shares any rooms with the user,
|
# Check if the changed user shares any rooms with the user,
|
||||||
# or if the changed user is the syncing user (as we always
|
# or if the changed user is the syncing user (as we always
|
||||||
# want to include device list updates of their own devices).
|
# want to include device list updates of their own devices).
|
||||||
if user_id == changed_user_id or any(
|
if user_id == changed_user_id or any(
|
||||||
rid in joined_rooms for rid in entries
|
rid in joined_rooms for rid in entries
|
||||||
):
|
):
|
||||||
users_that_have_changed.add(changed_user_id)
|
users_that_have_changed.add(changed_user_id)
|
||||||
else:
|
|
||||||
users_that_have_changed = (
|
|
||||||
await self._device_handler.get_device_changes_in_shared_rooms(
|
|
||||||
user_id,
|
|
||||||
sync_result_builder.joined_room_ids,
|
|
||||||
from_token=since_token,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Step 1b, check for newly joined rooms
|
|
||||||
for room_id in newly_joined_rooms:
|
|
||||||
joined_users = await self.store.get_users_in_room(room_id)
|
|
||||||
newly_joined_or_invited_or_knocked_users.update(joined_users)
|
|
||||||
|
|
||||||
# TODO: Check that these users are actually new, i.e. either they
|
|
||||||
# weren't in the previous sync *or* they left and rejoined.
|
|
||||||
users_that_have_changed.update(newly_joined_or_invited_or_knocked_users)
|
|
||||||
|
|
||||||
user_signatures_changed = (
|
|
||||||
await self.store.get_users_whose_signatures_changed(
|
|
||||||
user_id, since_token.device_list_key
|
|
||||||
)
|
|
||||||
)
|
|
||||||
users_that_have_changed.update(user_signatures_changed)
|
|
||||||
|
|
||||||
# Now find users that we no longer track
|
|
||||||
for room_id in newly_left_rooms:
|
|
||||||
left_users = await self.store.get_users_in_room(room_id)
|
|
||||||
newly_left_users.update(left_users)
|
|
||||||
|
|
||||||
# Remove any users that we still share a room with.
|
|
||||||
left_users_rooms = await self.store.get_rooms_for_users(newly_left_users)
|
|
||||||
for user_id, entries in left_users_rooms.items():
|
|
||||||
if any(rid in joined_rooms for rid in entries):
|
|
||||||
newly_left_users.discard(user_id)
|
|
||||||
|
|
||||||
return DeviceListUpdates(
|
|
||||||
changed=users_that_have_changed, left=newly_left_users
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
return DeviceListUpdates()
|
users_that_have_changed = (
|
||||||
|
await self._device_handler.get_device_changes_in_shared_rooms(
|
||||||
|
user_id,
|
||||||
|
sync_result_builder.joined_room_ids,
|
||||||
|
from_token=since_token,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Step 1b, check for newly joined rooms
|
||||||
|
for room_id in newly_joined_rooms:
|
||||||
|
joined_users = await self.store.get_users_in_room(room_id)
|
||||||
|
newly_joined_or_invited_or_knocked_users.update(joined_users)
|
||||||
|
|
||||||
|
# TODO: Check that these users are actually new, i.e. either they
|
||||||
|
# weren't in the previous sync *or* they left and rejoined.
|
||||||
|
users_that_have_changed.update(newly_joined_or_invited_or_knocked_users)
|
||||||
|
|
||||||
|
user_signatures_changed = await self.store.get_users_whose_signatures_changed(
|
||||||
|
user_id, since_token.device_list_key
|
||||||
|
)
|
||||||
|
users_that_have_changed.update(user_signatures_changed)
|
||||||
|
|
||||||
|
# Now find users that we no longer track
|
||||||
|
for room_id in newly_left_rooms:
|
||||||
|
left_users = await self.store.get_users_in_room(room_id)
|
||||||
|
newly_left_users.update(left_users)
|
||||||
|
|
||||||
|
# Remove any users that we still share a room with.
|
||||||
|
left_users_rooms = await self.store.get_rooms_for_users(newly_left_users)
|
||||||
|
for user_id, entries in left_users_rooms.items():
|
||||||
|
if any(rid in joined_rooms for rid in entries):
|
||||||
|
newly_left_users.discard(user_id)
|
||||||
|
|
||||||
|
return DeviceListUpdates(changed=users_that_have_changed, left=newly_left_users)
|
||||||
|
|
||||||
@trace
|
@trace
|
||||||
async def _generate_sync_entry_for_to_device(
|
async def _generate_sync_entry_for_to_device(
|
||||||
@ -1720,6 +1740,7 @@ class SyncHandler:
|
|||||||
since_token = sync_result_builder.since_token
|
since_token = sync_result_builder.since_token
|
||||||
|
|
||||||
if since_token and not sync_result_builder.full_state:
|
if since_token and not sync_result_builder.full_state:
|
||||||
|
# TODO Do not fetch room account data if it will be unused.
|
||||||
(
|
(
|
||||||
global_account_data,
|
global_account_data,
|
||||||
account_data_by_room,
|
account_data_by_room,
|
||||||
@ -1736,6 +1757,7 @@ class SyncHandler:
|
|||||||
sync_config.user
|
sync_config.user
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
# TODO Do not fetch room account data if it will be unused.
|
||||||
(
|
(
|
||||||
global_account_data,
|
global_account_data,
|
||||||
account_data_by_room,
|
account_data_by_room,
|
||||||
@ -1818,7 +1840,7 @@ class SyncHandler:
|
|||||||
self,
|
self,
|
||||||
sync_result_builder: "SyncResultBuilder",
|
sync_result_builder: "SyncResultBuilder",
|
||||||
account_data_by_room: Dict[str, Dict[str, JsonDict]],
|
account_data_by_room: Dict[str, Dict[str, JsonDict]],
|
||||||
) -> Tuple[AbstractSet[str], AbstractSet[str], AbstractSet[str], AbstractSet[str]]:
|
) -> Tuple[AbstractSet[str], AbstractSet[str]]:
|
||||||
"""Generates the rooms portion of the sync response. Populates the
|
"""Generates the rooms portion of the sync response. Populates the
|
||||||
`sync_result_builder` with the result.
|
`sync_result_builder` with the result.
|
||||||
|
|
||||||
@ -1831,24 +1853,22 @@ class SyncHandler:
|
|||||||
account_data_by_room: Dictionary of per room account data
|
account_data_by_room: Dictionary of per room account data
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Returns a 4-tuple describing rooms the user has joined or left, and users who've
|
Returns a 2-tuple describing rooms the user has joined or left.
|
||||||
joined or left rooms any rooms the user is in. This gets used later in
|
|
||||||
`_generate_sync_entry_for_device_list`.
|
|
||||||
|
|
||||||
Its entries are:
|
Its entries are:
|
||||||
- newly_joined_rooms
|
- newly_joined_rooms
|
||||||
- newly_joined_or_invited_or_knocked_users
|
|
||||||
- newly_left_rooms
|
- newly_left_rooms
|
||||||
- newly_left_users
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
since_token = sync_result_builder.since_token
|
since_token = sync_result_builder.since_token
|
||||||
user_id = sync_result_builder.sync_config.user.to_string()
|
user_id = sync_result_builder.sync_config.user.to_string()
|
||||||
|
|
||||||
# 1. Start by fetching all ephemeral events in rooms we've joined (if required).
|
# 1. Start by fetching all ephemeral events in rooms we've joined (if required).
|
||||||
if (
|
block_all_room_ephemeral = (
|
||||||
sync_result_builder.sync_config.filter_collection.blocks_all_room_ephemeral()
|
sync_result_builder.sync_config.filter_collection.blocks_all_rooms()
|
||||||
):
|
or sync_result_builder.sync_config.filter_collection.blocks_all_room_ephemeral()
|
||||||
|
)
|
||||||
|
if block_all_room_ephemeral:
|
||||||
ephemeral_by_room: Dict[str, List[JsonDict]] = {}
|
ephemeral_by_room: Dict[str, List[JsonDict]] = {}
|
||||||
else:
|
else:
|
||||||
now_token, ephemeral_by_room = await self.ephemeral_by_room(
|
now_token, ephemeral_by_room = await self.ephemeral_by_room(
|
||||||
@ -1870,7 +1890,7 @@ class SyncHandler:
|
|||||||
)
|
)
|
||||||
if not tags_by_room:
|
if not tags_by_room:
|
||||||
logger.debug("no-oping sync")
|
logger.debug("no-oping sync")
|
||||||
return set(), set(), set(), set()
|
return set(), set()
|
||||||
|
|
||||||
# 3. Work out which rooms need reporting in the sync response.
|
# 3. Work out which rooms need reporting in the sync response.
|
||||||
ignored_users = await self.store.ignored_users(user_id)
|
ignored_users = await self.store.ignored_users(user_id)
|
||||||
@ -1899,6 +1919,7 @@ class SyncHandler:
|
|||||||
# joined or archived).
|
# joined or archived).
|
||||||
async def handle_room_entries(room_entry: "RoomSyncResultBuilder") -> None:
|
async def handle_room_entries(room_entry: "RoomSyncResultBuilder") -> None:
|
||||||
logger.debug("Generating room entry for %s", room_entry.room_id)
|
logger.debug("Generating room entry for %s", room_entry.room_id)
|
||||||
|
# Note that this mutates sync_result_builder.{joined,archived}.
|
||||||
await self._generate_room_entry(
|
await self._generate_room_entry(
|
||||||
sync_result_builder,
|
sync_result_builder,
|
||||||
room_entry,
|
room_entry,
|
||||||
@ -1915,20 +1936,7 @@ class SyncHandler:
|
|||||||
sync_result_builder.invited.extend(invited)
|
sync_result_builder.invited.extend(invited)
|
||||||
sync_result_builder.knocked.extend(knocked)
|
sync_result_builder.knocked.extend(knocked)
|
||||||
|
|
||||||
# 5. Work out which users have joined or left rooms we're in. We use this
|
return set(newly_joined_rooms), set(newly_left_rooms)
|
||||||
# to build the device_list part of the sync response in
|
|
||||||
# `_generate_sync_entry_for_device_list`.
|
|
||||||
(
|
|
||||||
newly_joined_or_invited_or_knocked_users,
|
|
||||||
newly_left_users,
|
|
||||||
) = sync_result_builder.calculate_user_changes()
|
|
||||||
|
|
||||||
return (
|
|
||||||
set(newly_joined_rooms),
|
|
||||||
newly_joined_or_invited_or_knocked_users,
|
|
||||||
set(newly_left_rooms),
|
|
||||||
newly_left_users,
|
|
||||||
)
|
|
||||||
|
|
||||||
async def _have_rooms_changed(
|
async def _have_rooms_changed(
|
||||||
self, sync_result_builder: "SyncResultBuilder"
|
self, sync_result_builder: "SyncResultBuilder"
|
||||||
|
Loading…
Reference in New Issue
Block a user