-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
We don't cache the fact that a user has no devices #11586
Description
Spotted by @squahtx.
Some users, e.g. appservice users, won't have any devices whatsoever. If we query their homeserver to retrieve that user's devices, it should respond with an empty list of devices
. In the processing of that response, by the time we reach this line we have a devices
list from a successful response whose size is at most 999.
We transform devices
into a dictionary {d["device_id"]: d for d in devices}
. Assuming there are no repeated device_ids, this is a reversible transformation.
synapse/synapse/handlers/device.py
Lines 951 to 958 in e5cdb9e
cached_devices = await self.store.get_cached_devices_for_user(user_id) | |
if cached_devices == {d["device_id"]: d for d in devices}: | |
logging.info( | |
"Skipping device list resync for %s, as our cache matches already", | |
user_id, | |
) | |
devices = [] | |
ignore_devices = True |
Here, cached_devices
is:
synapse/synapse/storage/databases/main/devices.py
Lines 555 to 565 in 5305a5e
@cached() | |
async def get_cached_devices_for_user(self, user_id: str) -> Dict[str, JsonDict]: | |
devices = await self.db_pool.simple_select_list( | |
table="device_lists_remote_cache", | |
keyvalues={"user_id": user_id}, | |
retcols=("device_id", "content"), | |
desc="get_cached_devices_for_user", | |
) | |
return { | |
device["device_id"]: db_to_json(device["content"]) for device in devices | |
} |
Suppose we have never cached devices for this user, and that the devices
list is empty. Then cached_devices
will be an empty dictionary and so too will the transformed version of devices. Thus we'll set ignore_devices = True
and not cache the fact that this user has no devices.
Then, whenever someone wants this user's device again, we'll repeat the federation request again.