Skip to content

Commit 9c2e705

Browse files
committed
feat(event cache): shrink the linked chunk upon gappy syncs
1 parent 3267d3e commit 9c2e705

File tree

2 files changed

+43
-7
lines changed

2 files changed

+43
-7
lines changed

crates/matrix-sdk/src/event_cache/room/mod.rs

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ impl RoomEventCacheInner {
435435
} else {
436436
// Add the previous back-pagination token (if present), followed by the timeline
437437
// events themselves.
438-
let (_, sync_timeline_events_diffs) = state
438+
let ((), mut sync_timeline_events_diffs) = state
439439
.with_events_mut(|room_events| {
440440
// If we only received duplicated events, we don't need to store the gap: if
441441
// there was a gap, we'd have received an unknown event at the tail of
@@ -461,8 +461,21 @@ impl RoomEventCacheInner {
461461
})
462462
.await?;
463463

464+
if prev_batch.is_some() && !all_duplicates {
464465
// If there was a previous batch token, and there's at least one non-duplicated
466+
// new event, unload the chunks so it only contains the last
467+
// one; otherwise, there might be a valid gap in between, and
468+
// observers may not render it (yet). In this case, extend the
469+
// updates with those from the unload; the new updates include a `clear` (as of
470+
// 2025-02-24), so they will remove all the previous ones first.
471+
//
465472
// We must do this *after* the above call to `.with_events_mut`, so the new
473+
// events and gaps are properly persisted to storage.
474+
if let Some(new_events_diffs) = state.shrink_to_last_chunk().await? {
475+
sync_timeline_events_diffs.extend(new_events_diffs);
476+
}
477+
}
478+
466479
{
467480
// Fill the AllEventsCache.
468481
let mut all_events = self.all_events.write().await;
@@ -1690,6 +1703,8 @@ mod tests {
16901703
#[cfg(not(target_arch = "wasm32"))] // This uses the cross-process lock, so needs time support.
16911704
#[async_test]
16921705
async fn test_no_useless_gaps() {
1706+
use crate::event_cache::room::LoadMoreEventsBackwardsOutcome;
1707+
16931708
let room_id = room_id!("!galette:saucisse.bzh");
16941709

16951710
let client = MockClientBuilder::new("http://localhost".to_owned()).build().await;
@@ -1725,7 +1740,7 @@ mod tests {
17251740
.unwrap();
17261741

17271742
{
1728-
let state = room_event_cache.inner.state.read().await;
1743+
let mut state = room_event_cache.inner.state.write().await;
17291744

17301745
let mut num_gaps = 0;
17311746
let mut num_events = 0;
@@ -1737,6 +1752,26 @@ mod tests {
17371752
}
17381753
}
17391754

1755+
// The limited sync unloads the chunk, so it will appear as if there are only
1756+
// the events.
1757+
assert_eq!(num_gaps, 0);
1758+
assert_eq!(num_events, 1);
1759+
1760+
// But if I manually reload more of the chunk, the gap will be present.
1761+
assert_matches!(
1762+
state.load_more_events_backwards().await.unwrap(),
1763+
LoadMoreEventsBackwardsOutcome::Gap
1764+
);
1765+
1766+
num_gaps = 0;
1767+
num_events = 0;
1768+
for c in state.events().chunks() {
1769+
match c.content() {
1770+
ChunkContent::Items(items) => num_events += items.len(),
1771+
ChunkContent::Gap(_) => num_gaps += 1,
1772+
}
1773+
}
1774+
17401775
// The gap must have been stored.
17411776
assert_eq!(num_gaps, 1);
17421777
assert_eq!(num_events, 1);

crates/matrix-sdk/tests/integration/event_cache.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,15 +1302,16 @@ async fn test_no_gap_stored_after_deduplicated_backpagination() {
13021302
assert_let_timeout!(
13031303
Ok(RoomEventCacheUpdate::UpdateTimelineEvents { diffs, .. }) = stream.recv()
13041304
);
1305-
assert_eq!(diffs.len(), 2);
1305+
assert_eq!(diffs.len(), 4);
13061306

1307-
// The linked chunk is unloaded, because of the limited sync with a gap:
1308-
// It's first cleared…
1309-
assert_matches!(&diffs[0], VectorDiff::Clear);
1307+
// The first two diffs are for the gap and the new events, but they don't really
1308+
// matter in this test, because then, the linked chunk is unloaded, causing
1309+
// a clear:
1310+
assert_matches!(&diffs[2], VectorDiff::Clear);
13101311

13111312
// Then the latest event chunk is reloaded.
13121313
// `$ev1`, `$ev2` and `$ev3` are added.
1313-
assert_matches!(&diffs[1], VectorDiff::Append { values: events } => {
1314+
assert_matches!(&diffs[3], VectorDiff::Append { values: events } => {
13141315
assert_eq!(events.len(), 3);
13151316
assert_eq!(events[0].event_id().unwrap().as_str(), "$1");
13161317
assert_eq!(events[1].event_id().unwrap().as_str(), "$2");

0 commit comments

Comments
 (0)