Add the reads persisting events needs, in Rust

`PersistReader` wraps a `SyncReader` and adds the reads the persist
controller makes before its write transaction: forward and state DAG
extremities, the prev event walks of `_get_events_which_are_prevs` and
`_get_prevs_before_rejected`, `have_seen_events`, memberships by event ID,
`is_local_host_in_room_ignoring_users`, the room version, the sliding sync
joined room check, `get_last_event_pos_in_room` and the soft failed sticky
events. None of them is cached. Each runs once per chunk.

The chain cover reads are free functions over a `Querier`, not reader
methods. The chain cover step reads, allocates chain IDs and writes in one
transaction, so they must run on that transaction's connection. To allow
that, `WriteTxn` now implements `Querier`. A `WriteError` that passes
through `anyhow` on the way out comes back as itself, so a conflict is still
retried.

The persister builds its own `SyncStore` over the shared caches.
`tests/storage/test_persist_reader.py` runs each read against the Python
method or statement it ports, on the native driver.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UHKYPSc37kWqGACn9aKxKL
This commit is contained in:
Erik JohnstonandClaude Opus 5.5 committed 2026-10-16 14:08:18 +00:00
1 parent 419c47e91d
commit 1afdeb20df
8 files changed
+1935 -17

No files matched your search

+8
View File
@@ -29,6 +29,7 @@ use crate::{
native_pool::NativePool,
store::Store,
stream_ids::{PyStreamIdTracker, StreamIdTracker},
sync_store::{SyncStore, SyncStoreConfig},
},
types::state_filter::state_map_to_py,
};
@@ -50,6 +51,9 @@ pub(super) struct PersisterInner {
pub pool: NativePool,
pub runtime: RustRuntime,
pub store: Arc<Store>,
/// The sync store over the same caches, which the
/// [`super::reader::PersistReader`] builds on.
pub sync: Arc<SyncStore>,
pub events_stream: Arc<StreamIdTracker>,
pub backfill_stream: Arc<StreamIdTracker>,
pub cache_stream: Arc<StreamIdTracker>,
@@ -93,6 +97,10 @@ impl Persister {
inner: Arc::new(PersisterInner {
pool: NativePool::new(connection_pool, "persist_db_pool"),
runtime,
sync: Arc::new(SyncStore::new(
Arc::clone(&store.caches),
SyncStoreConfig::from_config(&homeserver.config(py)?),
)),
store,
events_stream: tracker(intern!(py, "_stream_id_gen"))?,
backfill_stream: tracker(intern!(py, "_backfill_id_gen"))?,