Skip to content

Conversation

@Hywan
Copy link
Member

@Hywan Hywan commented Nov 11, 2025

The EventCache stores and organises all events. A RoomEventCache represents a subset of the EventCache, be all events associated to a particular room. That's the type used by each Room to store and organise its events. The EventCacheStore is the type representing the store for the EventCache. It is used by RoomEventCache to represent the stored data. RoomEventCache also has in-memory data. In-memory data are always in-sync with data in the store. The EventCacheStore is behind a CrossProcessLock, a special lock that protects data from being acquired across several processes. So far, so good.

We've recently introduced the possibility for a cross-process to be invalidated/to be dirty, see #4874. When a CrossProcessLock is obtained, it is now possible to know if another process obtained it before, thus invalidating the loaded data from the store we might have in-memory. It is a sign we need to refresh the in-memory data.

This is what this set of patches is doing: we are reacting to a dirty cross-process lock and refreshing the in-memory state of RoomEventCache accordingly.

This set of patches must be reviewed one-by-one to understand the modifications and their impact. The tl;dr is the following:

  • RoomEventCacheState becomes RoomEventCacheStateLock, representing 2 locks at once: the per-thread lock over the state, and the cross-process lock over the store,
  • RoomEventCacheStateInner becomes RoomEventCacheStateLockInner,
  • RoomEventCacheInner::state holds a RoomEventCacheLock instead of a RwLock<RoomEventCacheState>,
  • RoomEventCacheLock implements a read and a write methods, to respectively obtain a read and a write lock. These operations are no longer infallible. It impacts a couple of callers, but nothing fancy.

The impacted code is mostly internal code.

Todo

  • Ensure VectorDiffs are broadcasted to the subcribers. This isn't done by shrink_to_last_chunk because it's supposed to run when no more subscribers are listening. We must handle this, I forgot!

@Hywan Hywan mentioned this pull request Nov 11, 2025
10 tasks
@Hywan Hywan force-pushed the feat-cross-process-lock-event-cache branch 4 times, most recently from d6bf9c0 to b13c1fa Compare November 18, 2025 08:26
@codecov
Copy link

codecov bot commented Nov 18, 2025

Codecov Report

❌ Patch coverage is 71.68142% with 64 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.60%. Comparing base (4ae82dd) to head (cf881ab).
⚠️ Report is 14 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
crates/matrix-sdk-common/src/cross_process_lock.rs 79.20% 4 Missing and 22 partials ⚠️
crates/matrix-sdk-ui/src/timeline/tasks.rs 0.00% 12 Missing ⚠️
crates/matrix-sdk/src/event_cache/redecryptor.rs 25.00% 0 Missing and 6 partials ⚠️
crates/matrix-sdk/src/event_cache/mod.rs 73.68% 1 Missing and 4 partials ⚠️
crates/matrix-sdk-base/src/client.rs 0.00% 0 Missing and 3 partials ⚠️
...rates/matrix-sdk-ui/src/timeline/controller/mod.rs 25.00% 0 Missing and 3 partials ⚠️
crates/matrix-sdk/src/event_cache/pagination.rs 70.00% 0 Missing and 3 partials ⚠️
crates/matrix-sdk-base/src/media/store/mod.rs 33.33% 2 Missing ⚠️
...rates/matrix-sdk-base/src/event_cache/store/mod.rs 90.00% 0 Missing and 1 partial ⚠️
...matrix-sdk-ui/src/timeline/pinned_events_loader.rs 0.00% 0 Missing and 1 partial ⚠️
... and 2 more
Additional details and impacted files
@@           Coverage Diff            @@
##             main    #5856    +/-   ##
========================================
  Coverage   88.60%   88.60%            
========================================
  Files         363      363            
  Lines      102926   103479   +553     
  Branches   102926   103479   +553     
========================================
+ Hits        91194    91684   +490     
- Misses       7490     7516    +26     
- Partials     4242     4279    +37     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@codspeed-hq
Copy link

codspeed-hq bot commented Nov 18, 2025

CodSpeed Performance Report

Merging #5856 will not alter performance

Comparing Hywan:feat-cross-process-lock-event-cache (cf881ab) with main (b1eaa5e)

Summary

✅ 50 untouched

@Hywan Hywan force-pushed the feat-cross-process-lock-event-cache branch 7 times, most recently from 08d2859 to 2305356 Compare November 19, 2025 09:24
Hywan added 16 commits November 19, 2025 11:21
This patch renames the `CrossProcessLockKind` type to
`CrossProcessLockState`.
This patch adds a `#[must_use]` attribute on `CrossProcessLockGuard` and
`CrossProcessLockState` to avoid a misuse.
This patch adds the `CrossProcessLockState::map` method along with its
companion `MappedCrossProcessLockState` type. The idea is to facilitate
the creation of custom `CrossProcessLockState`-like type in various
usage of the cross-process lock.
This patch updates `EventCacheStoreLock::lock()` to return an
`EventCacheStoreLockState` instead of an `EventCacheStoreLockGuard`, so
that the caller has to handle dirty locks.
This patch replicates the `is_dirty` and `clear_dirty` methods from
`CrossProcessLock` to `CrossProcessLockGuard`. It allows to get an
access to this API from a guard when one doesn't have the cross-process
lock at hand.
…store.

This patch changes `EventCacheStoreLockState` to own a clone of
the inner store. It helps to remove the `'a` lifetime, and so it
“disconnects” from the lifetime of the store.
This patch implements `Clone` for `CrossProcessLockGuard`.
This patch implements `Clone` for `EventCacheStoreLockGuard`.
This patch extracts fields from `RoomEventCacheState` and move them
into `RoomEventCacheStateLock`. This lock provides 2 methods: `read`
and `write`, respectively to acquire a read-only lock, and a write-only
lock, represented by the `RoomEventCacheStateLockReadGuard` and the
`RoomEventCacheStateLockWriteGuard` types.

All “public” methods on `RoomEventCacheState` now are facade to the read
and write guards.

This refactoring makes the code to compile with the last change in
`EventCacheStore::lock`, which now returns a `EventCacheStoreLockState`.
The next step is to re-load `RoomEventCacheStateLock` when the lock is
dirty! But before doing that, we need this new mechanism to centralise
the management of the store lock.
… dirty.

This patch updates the `RoomEventCacheStateLock::read` and `write`
methods to reset the state when the cross-process lock is dirty.
@Hywan Hywan force-pushed the feat-cross-process-lock-event-cache branch from 2305356 to 8ee41f4 Compare November 19, 2025 10:21
This patch replaces `sleep` by `yield_now`, which has the same effect in
this case, and makes the tests run faster.
This patch implements `RoomEventCacheStateLockWriteGuard::downgrade` to
simplify the code a little bit.
This patch fixes a problem found in a test (not commited yet) where it
was impossible to do multiple calls to `read` if the first guard was
still alive. See the comments to learn more.
This patch adds the new `test_reset_when_dirty` test, which ensures
the state is correctly reset when the cross-process lock over the store
becomes dirty.
@Hywan Hywan marked this pull request as ready for review November 19, 2025 16:13
@Hywan Hywan requested a review from a team as a code owner November 19, 2025 16:13
@Hywan Hywan requested review from poljar and removed request for a team November 19, 2025 16:13
// Lock is dirty, not a problem, it's the first time we are creating this state, no
// need to refresh.
EventCacheStoreLockState::Dirty(guard) => {
EventCacheStoreLockGuard::clear_dirty(&guard);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: I must add a test for this case, and see the dirty marker is reset.

});
}
// All good now, mark the cross-process lock as non-dirty.
EventCacheStoreLockGuard::clear_dirty(&guard.store);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: I must add an assertion to see if the dirty marker is reset.

current = *pred_meta;
}
// All good now, mark the cross-process lock as non-dirty.
EventCacheStoreLockGuard::clear_dirty(&guard.store);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: I must add an assertion to see if the dirty marker is reset.

@Hywan Hywan requested a review from andybalaam November 19, 2025 16:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant