From 5b756d3c9db06bfa123e6dfd815d7b1bd89bffde Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Mon, 18 May 2026 18:47:16 +0200 Subject: [PATCH] refactor(sdk): R2D2 replaces UTD on `PinnedEventsCache` without involving `RoomEventCache`. This patch updates R2D2 to fetch the `PinnedEventsCache` from `EventCache` without using `RoomEventCache`. --- .../matrix-sdk/src/event_cache/caches/mod.rs | 10 +++++++ .../event_cache/caches/pinned_events/mod.rs | 2 +- crates/matrix-sdk/src/event_cache/mod.rs | 13 ++++++++++ .../matrix-sdk/src/event_cache/redecryptor.rs | 26 ++++++++++--------- 4 files changed, 38 insertions(+), 13 deletions(-) diff --git a/crates/matrix-sdk/src/event_cache/caches/mod.rs b/crates/matrix-sdk/src/event_cache/caches/mod.rs index 0ea9c0ab1..a9026d225 100644 --- a/crates/matrix-sdk/src/event_cache/caches/mod.rs +++ b/crates/matrix-sdk/src/event_cache/caches/mod.rs @@ -201,6 +201,16 @@ impl Caches { }) } + /// Get a [`PinnedEventsCache`] if it has been initialised. + /// + /// [`PinnedEventsCache`]: pinned_events::PinnedEventsCache + #[cfg(feature = "e2e-encryption")] + pub(super) fn pinned_events_without_initialisation( + &self, + ) -> Option<&pinned_events::PinnedEventsCache> { + self.pinned_events.get() + } + /// Update all the event caches with a [`JoinedRoomUpdate`]. pub(super) async fn handle_joined_room_update(&self, updates: JoinedRoomUpdate) -> Result<()> { let Self { room, threads, pinned_events, internals } = &self; diff --git a/crates/matrix-sdk/src/event_cache/caches/pinned_events/mod.rs b/crates/matrix-sdk/src/event_cache/caches/pinned_events/mod.rs index fd57b53ac..121a5e55a 100644 --- a/crates/matrix-sdk/src/event_cache/caches/pinned_events/mod.rs +++ b/crates/matrix-sdk/src/event_cache/caches/pinned_events/mod.rs @@ -530,7 +530,7 @@ impl PinnedEventsCache { /// list of decrypted events, and replace them, while alerting observers /// about the update. #[cfg(feature = "e2e-encryption")] - pub(in crate::event_cache) async fn replace_utds(&self, events: &[ResolvedUtd]) -> Result<()> { + pub(in super::super) async fn replace_utds(&self, events: &[ResolvedUtd]) -> Result<()> { let mut guard = self.inner.state.write().await?; if guard.state.chunk.replace_utds(events) { diff --git a/crates/matrix-sdk/src/event_cache/mod.rs b/crates/matrix-sdk/src/event_cache/mod.rs index d1a5ac272..14878b448 100644 --- a/crates/matrix-sdk/src/event_cache/mod.rs +++ b/crates/matrix-sdk/src/event_cache/mod.rs @@ -402,6 +402,19 @@ impl EventCache { Ok((caches_for_room.pinned_events()?.clone(), drop_handles)) } + + /// Return a pinned-events-specific view over the [`EventCache`] if it has + /// been initialised. + #[cfg(feature = "e2e-encryption")] + async fn pinned_events_without_initialisation( + &self, + room_id: &RoomId, + ) -> Result> { + let caches_for_room = self.inner.all_caches_for_room(room_id).await?; + + Ok(caches_for_room.pinned_events_without_initialisation().cloned()) + } + /// Cleanly clear all the rooms' event caches. /// /// This will notify any live observers that the room has been cleared. diff --git a/crates/matrix-sdk/src/event_cache/redecryptor.rs b/crates/matrix-sdk/src/event_cache/redecryptor.rs index c553a6fbc..0b5957924 100644 --- a/crates/matrix-sdk/src/event_cache/redecryptor.rs +++ b/crates/matrix-sdk/src/event_cache/redecryptor.rs @@ -370,14 +370,14 @@ impl EventCache { // Phase 1: under the room state write lock, collect cache handles and // perform all room-linked-chunk mutations. We deliberately do NOT call - // replace_utds() on event-focused/pinned caches here to avoid an ABBA deadlock: - // pagination holds an event-focused cache lock and then tries to acquire the - // room state lock (via `save_events`), while this method would hold the - // room state lock and try to acquire event-focused cache locks. - let (pinned_cache, ef_caches) = { + // replace_utds() on event-focused/pinned-evenst caches here to avoid an ABBA + // deadlock: pagination holds an event-focused cache lock and then tries + // to acquire the room state lock (via `save_events`), while this method + // would hold the room state lock and try to acquire event-focused cache + // locks. + let ef_caches = { let mut state = room_cache.state().write().await?; - let pinned_cache = state.pinned_events_cache().cloned(); let ef_caches: Vec<_> = state.event_focused_caches().cloned().collect(); // Consider the room linked chunk. @@ -416,15 +416,17 @@ impl EventCache { Some(RoomEventCacheGenericUpdate { room_id: room_id.to_owned() }), ); - (pinned_cache, ef_caches) + ef_caches }; // Room state write lock is dropped here. - // Phase 2: replace UTDs in pinned and event-focused caches WITHOUT - // holding the room state lock. These caches have their own internal - // locks and don't need the room state lock. - if let Some(pinned_cache) = pinned_cache { - pinned_cache.replace_utds(&events).await?; + // Phase 2: replace UTDs in pinned-events and event-focused caches + // WITHOUT holding the room state lock. These caches have their own + // internal locks and don't need the room state lock. + if let Ok(Some(pinned_events_cache)) = + self.pinned_events_without_initialisation(room_id).await + { + pinned_events_cache.replace_utds(&events).await?; } // TODO: This ain't great for performance; there shouldn't be that many