@@ -435,7 +435,7 @@ impl RoomEventCacheInner {
435
435
} else {
436
436
// Add the previous back-pagination token (if present), followed by the timeline
437
437
// events themselves.
438
- let ( _ , sync_timeline_events_diffs) = state
438
+ let ( ( ) , mut sync_timeline_events_diffs) = state
439
439
. with_events_mut ( |room_events| {
440
440
// If we only received duplicated events, we don't need to store the gap: if
441
441
// there was a gap, we'd have received an unknown event at the tail of
@@ -461,8 +461,20 @@ impl RoomEventCacheInner {
461
461
} )
462
462
. await ?;
463
463
464
+ if prev_batch. is_some ( ) && !all_duplicates {
464
465
// 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, override the
469
+ // updates with those from the unload.
470
+ //
465
471
// We must do this *after* the above call to `.with_events_mut`, so the new
472
+ // events and gaps are properly persisted to storage.
473
+ if let Some ( new_events_diffs) = state. shrink_to_last_chunk ( ) . await ? {
474
+ sync_timeline_events_diffs = new_events_diffs;
475
+ }
476
+ }
477
+
466
478
{
467
479
// Fill the AllEventsCache.
468
480
let mut all_events = self . all_events . write ( ) . await ;
@@ -1687,6 +1699,8 @@ mod tests {
1687
1699
#[ cfg( not( target_arch = "wasm32" ) ) ] // This uses the cross-process lock, so needs time support.
1688
1700
#[ async_test]
1689
1701
async fn test_no_useless_gaps ( ) {
1702
+ use crate :: event_cache:: room:: LoadMoreEventsBackwardsOutcome ;
1703
+
1690
1704
let room_id = room_id ! ( "!galette:saucisse.bzh" ) ;
1691
1705
1692
1706
let client = MockClientBuilder :: new ( "http://localhost" . to_owned ( ) ) . build ( ) . await ;
@@ -1722,7 +1736,7 @@ mod tests {
1722
1736
. unwrap ( ) ;
1723
1737
1724
1738
{
1725
- let state = room_event_cache. inner . state . read ( ) . await ;
1739
+ let mut state = room_event_cache. inner . state . write ( ) . await ;
1726
1740
1727
1741
let mut num_gaps = 0 ;
1728
1742
let mut num_events = 0 ;
@@ -1734,6 +1748,26 @@ mod tests {
1734
1748
}
1735
1749
}
1736
1750
1751
+ // The limited sync unloads the chunk, so it will appear as if there are only
1752
+ // the events.
1753
+ assert_eq ! ( num_gaps, 0 ) ;
1754
+ assert_eq ! ( num_events, 1 ) ;
1755
+
1756
+ // But if I manually reload more of the chunk, the gap will be present.
1757
+ assert_matches ! (
1758
+ state. load_more_events_backwards( ) . await . unwrap( ) ,
1759
+ LoadMoreEventsBackwardsOutcome :: Gap
1760
+ ) ;
1761
+
1762
+ num_gaps = 0 ;
1763
+ num_events = 0 ;
1764
+ for c in state. events ( ) . chunks ( ) {
1765
+ match c. content ( ) {
1766
+ ChunkContent :: Items ( items) => num_events += items. len ( ) ,
1767
+ ChunkContent :: Gap ( _) => num_gaps += 1 ,
1768
+ }
1769
+ }
1770
+
1737
1771
// The gap must have been stored.
1738
1772
assert_eq ! ( num_gaps, 1 ) ;
1739
1773
assert_eq ! ( num_events, 1 ) ;
0 commit comments