mirror of
https://github.com/element-hq/synapse.git
synced 2026-11-04 19:57:45 +00:00
With the database work cached, converting the state sets from Python dicts was the largest piece of a warm resolution: 5,010 entries pulled out of tuples and interned, under the GIL, before the future starts, and 2,505 entries built into a dict on the way back. Every group's state was converted again on every resolution it took part in. The handler gains resolve_state_groups, which takes the state groups by ID with their state, as StateResolutionHandler.resolve_state_groups receives them, and keeps each group's converted StateMap in a cache keyed on the group ID. State groups are immutable and their IDs are never reused, so an entry can only go stale by its group being deleted, which makes it dead weight rather than wrong. The cache is cleared on a room purge with the others. A group given with fewer entries than its cached state is a filtered one: it is converted for that call and does not replace the full map. The result is returned in the shape of a _StateCacheEntry, chosen as _make_state_cache_entry does: the input group the resolved state equals, else the input group it differs least from and the difference, else the state itself. So the common cases cross the boundary as a group ID or a small delta rather than the whole state. StateResolutionHandler.resolve_state_groups uses it in "on" mode, with the usual fallback to Python for rooms without a chain cover index. Shadow mode keeps comparing through resolve_events_with_store. The state sets are now shared maps inside the Rust, so a cached map and a converted one are handled alike. On the benchmark room (2,000 members, 1,000 conflicted events) a warm resolution through the state groups takes 9 to 11 ms end to end once the groups' state is cached, from 15 to 19 through the flat entry point; Python warm is 37 to 44. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ULdieJyQoHNzeHq42H2M1p