Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

We don't cache the fact that a user has no devices #11586

Closed
DMRobertson opened this issue Dec 15, 2021 · 3 comments · Fixed by #11587
Closed

We don't cache the fact that a user has no devices #11586

DMRobertson opened this issue Dec 15, 2021 · 3 comments · Fixed by #11587
Labels
S-Minor Blocks non-critical functionality, workarounds exist. T-Defect Bugs, crashes, hangs, security vulnerabilities, or other reported issues.

Comments

@DMRobertson
Copy link
Contributor

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.

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:

@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.

@DMRobertson
Copy link
Contributor Author

The problem here is that the DB doesn't have a way to distinguish "this user has no devices" from "I've not got a cache entry for this user".

@clokep clokep added S-Minor Blocks non-critical functionality, workarounds exist. T-Defect Bugs, crashes, hangs, security vulnerabilities, or other reported issues. labels Dec 15, 2021
@DMRobertson
Copy link
Contributor Author

We suspect this contributed to performance problems on the master today, after a room on t2bot.io containing bridged (deviceless!) users had encryption enabled.

@DMRobertson
Copy link
Contributor Author

the DB doesn't have a way to distinguish "this user has no devices" from "I've not got a cache entry for this user".

This may be incorrect. Sean noted that there's a device_lists_remote_extremeties table which tracks username and stream ids. When is this written to?

It looks like every write to the cache is matched by a write to the extremities table. Promising!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
S-Minor Blocks non-critical functionality, workarounds exist. T-Defect Bugs, crashes, hangs, security vulnerabilities, or other reported issues.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants