mirror of
https://github.com/element-hq/synapse.git
synced 2026-11-04 17:47:28 +00:00
The first commit of phase 2 of the event persistence plan (`transaction` level). `rust/src/persist/txn/` will hold the port of `_persist_events_txn`. This commit adds its driver: the share lock on the room's `rooms` row, the cache updates Python queues for every event up front, and dropping duplicate events. It returns the events left for the steps still in Python. `tests/storage/test_rust_persist_txn.py` builds the same DAG in two rooms. Room A persists in Python. Room B prepares in Rust, runs the Rust part of the transaction in its own committed transaction through `Persister.persist_events_txn_for_test`, and then runs the Python steps after it. The test compares the rows of every table the transaction writes, after normalising room and event IDs, stream positions, state groups and chain IDs, and compares the cache updates both rooms asked for. Each later commit moves more steps from the Python half to the Rust half, in transaction order, until the facade runs the whole transaction. Mutating the driver (dropping the redaction invalidation, the relation, the state key, or the outlier rule for duplicates) fails the comparison. Two open items from phase 1: - Reads before the transaction now retry. Python runs each read in a `runInteraction` that retries a lost connection or a cancelled statement. `Persister.prepare_chunk` now prepares the whole chunk again on such an error, up to five attempts. That is safe because its only write, bumping the state groups it uses, can be repeated. The reader and the state resolution store keep the pool's error as the cause, so `is_retryable_error` can classify it. A `WriteError` does not count, as its write interaction has already retried, and `WriteError::from_pg` shares the classification. - The Rust persister needs the state tables in the main database, as it reads and writes both in one transaction. `Persister::for_homeserver` now checks for that, and the persister is off when they are apart. Also fixed in the dispatch: at `off`, `_prepare_chunk` ran Rust when a persister existed. That only happens when a test changes the level at runtime. The twin test does exactly that. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LXMkcZVkcZhi21augBff4a