Files
synapse/tests
Erik JohnstonandClaude Opus 5.5 aecc892ea3 Persist sticky events and sliding sync bump stamps in Rust
The fifth commit of phase 2. The Rust transaction now runs the rest of
`_persist_events_txn`, but for the event cache prefill (`_add_to_cache`)
and the profile updates, which stay in Python.

- `txn/sticky.rs`: `insert_sticky_events_txn` for the chunk's new
  events, and `un_soft_fail_sticky_events_txn` for the events
  `compute_sticky_events_to_un_soft_fail` found in prepare. A
  de-outliered sticky event becomes sticky inside `update_outliers`, as
  in Python, so the chunk's redactions come after it. As in Python, an
  event with a zero sticky duration is not tried there.
- `txn/sliding_sync.rs`: the latest stream ordering and bump stamp of
  the room's `sliding_sync_joined_rooms` row.
- `txn/streams.rs`: what was `CacheStream`, now `TxnStream` for any
  stream the transaction takes IDs from, several at a time. The sticky
  events stream is the second. Its IDs come back unfinished in
  `PersistEffects.sticky_stream_ids`. Python finishes them once the
  caches are invalidated, notifies replication and, as the stream has
  writers, updates `stream_positions`, as `get_next_mult_txn`'s
  callbacks do. A failed attempt's IDs are finished as for the cache
  stream.

`persist_events_txn` returns the events left. The test entry no longer
returns the de-outliered events.

Python's `un_soft_fail_sticky_events_txn` gave the events their new
stream IDs in a set's order. It now keeps their order in the stream, by
`event_stream_ordering`, with any event without a row last, by event ID.
Rust does the same, which lets the twin test compare several events
lifted at once.

The new scenarios found a Python bug, which Rust keeps. A de-outliered
sticky event's `sticky_events` row has the stream ordering of the chunk
that de-outliered it, but its `events` row keeps the one it was first
persisted with. `delete_sticky_events_txn` looks for the latter, so a
redaction of the event, in that chunk or any later one, leaves it
sticky until it expires.

The twin harness:

- records the stream IDs the applier finishes and the notifiers it
  calls, rather than modelling them from the effects
- merges each persist's finished IDs per stream into one call, and
  compares its notifiers by whether they were called. Python queues
  them per allocation of IDs, and the effects do each once.
- names a background process by what it runs: an ID generator's
  `stream_positions` update by its stream, any other by its description

New twin scenarios:

- sticky events in one chunk, one of them expired
- a sticky outlier, de-outliered; de-outliered and redacted in one
  chunk; de-outliered with a new sticky event in one chunk
- soft-failed sticky events lifted when their sender joins, one and
  three at once
- a rejected sticky event, a backfilled one, and one redacted in its
  own chunk

A prereqs test checks that applying the effects finishes the sticky
events stream IDs after the event cache invalidations, then notifies,
and updates `stream_positions`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LXMkcZVkcZhi21augBff4a
2026-10-17 16:51:28 +00:00
..
2026-09-18 12:00:45 +01:00
2026-10-14 13:35:25 +00:00