-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Fix bug in device list caching when remote users leave rooms #13749
Changes from 5 commits
18e5f60
766b136
17dd441
10595c8
5a12cb7
d928704
b234f4d
f104cc1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Fix a long standing bug where device lists would remain cached when remote users left and rejoined the last room shared with the local homeserver. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -175,6 +175,33 @@ async def query_devices( | |
user_ids_not_in_cache, | ||
remote_results, | ||
) = await self.store.get_user_devices_from_cache(query_list) | ||
|
||
# Check that the homeserver still shares a room with all cached users. | ||
# Note that this check may be slightly racy when a remote user leaves a | ||
# room after we have fetched their cached device list. In the worst case | ||
# we will do extra federation queries for devices that we had cached. | ||
cached_users = set(remote_results.keys()) | ||
valid_cached_users = ( | ||
await self.store.get_users_server_still_shares_room_with( | ||
remote_results.keys() | ||
) | ||
) | ||
invalid_cached_users = cached_users - valid_cached_users | ||
if invalid_cached_users: | ||
# Fix up results. If we get here there may be bugs in device list | ||
# tracking. | ||
# TODO: is this actually useful? it doesn't fix the case where a | ||
# remote user rejoins a room and we query their device list | ||
# after. | ||
user_ids_not_in_cache.update(invalid_cached_users) | ||
for invalid_user_id in invalid_cached_users: | ||
remote_results.pop(invalid_user_id) | ||
logger.error( | ||
"Devices for %s were cached, but the server no longer shares " | ||
"any rooms with them. The cached device lists are stale.", | ||
invalid_cached_users, | ||
) | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not fully convinced this check is useful, because it'll only catch It's also slightly racy and can trigger spuriously when a remote user leaves a room while we're in the middle of handling the request. Do we want to keep it or remove it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think its valid for clients to do a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That sounds plausible! |
||
for user_id, devices in remote_results.items(): | ||
user_devices = results.setdefault(user_id, {}) | ||
for device_id, device in devices.items(): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -598,9 +598,9 @@ async def _persist_event_batch( | |
# room | ||
state_delta_for_room: Dict[str, DeltaState] = {} | ||
|
||
# Set of remote users which were in rooms the server has left. We | ||
# should check if we still share any rooms and if not we mark their | ||
# device lists as stale. | ||
# Set of remote users which were in rooms the server has left or who may | ||
# have left rooms the server is in. We should check if we still share any | ||
# rooms and if not we mark their device lists as stale. | ||
potentially_left_users: Set[str] = set() | ||
|
||
if not backfilled: | ||
|
@@ -725,6 +725,20 @@ async def _persist_event_batch( | |
current_state = {} | ||
delta.no_longer_in_room = True | ||
|
||
# Add all remote users that might have left rooms. | ||
potentially_left_users.update( | ||
user_id | ||
for event_type, user_id in delta.to_delete | ||
if event_type == EventTypes.Member | ||
and not self.is_mine_id(user_id) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Needs #13746, otherwise we can raise errors when there are malformed user IDs in the room state. |
||
) | ||
potentially_left_users.update( | ||
user_id | ||
for event_type, user_id in delta.to_insert.keys() | ||
if event_type == EventTypes.Member | ||
and not self.is_mine_id(user_id) | ||
) | ||
|
||
state_delta_for_room[room_id] = delta | ||
|
||
await self.persist_events_store._persist_events_and_state_updates( | ||
|
Uh oh!
There was an error while loading. Please reload this page.