mirror of
https://github.com/element-hq/synapse.git
synced 2026-11-12 12:08:18 +00:00
With the event cache warm, the chain cover queries were what was left of the database work in a resolution: the position of every event in the state sets, and the links out of every chain they are on. Both can be cached. A chain position never changes once assigned, so it is cached before the transaction commits, and dropped with the event in case the event is purged and received again. The links out of a chain only grow, at the end: an event appended at sequence number n adds links out of (chain, n) and changes nothing below. So links read while the chain was known to reach n are complete for every walk that starts at or below n, and the cache keeps that bound with them. A walk that needs a chain beyond its bound refetches it. Both caches go on a room purge, which deletes the room's chains and links. The chain cover walk now gathers links first (from the cache, following the links a backwards walk would follow so reached chains are gathered too, and from the database for the rest) and then walks them once. The Python walks each batch of its recursive query as it arrives, but a batch is closed under reachability, so walking the union comes to the same thing. Fetching only what a sequence-aware walk reaches, rather than the full reachability closure, leaves the auth difference and the v2.1 conflicted subgraph unchanged: any forwards path that ends inside a backwards-reachable range runs through chains the backwards walks reached, below their bounds. The trial comparison against the Python runs every case through a handler's caches too. The three store-side caches are bundled as StateResCaches, so the store and the invalidation hooks treat them as one. The integer-keyed maps in the chain cover code and the interner use FxHash, and the reverse position map is one flat map, which together are worth 2 ms on the warm path of the benchmark. The stats gained the cache hit counts and timings for the auth chain difference, event loading and the connection. On the benchmark room (2,000 members, 1,000 conflicted events) a warm resolution runs no chain queries and takes 14 to 20 ms end to end, from 27 to 32 with the event cache alone; Python warm is 38 to 41. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ULdieJyQoHNzeHq42H2M1p