@@ -631,11 +631,15 @@ impl RoomEventCacheInner {
631
631
}
632
632
633
633
/// Internal type to represent the output of
634
- /// `RoomEventCacheState::load_more_events_backwards`.
634
+ /// [ `RoomEventCacheState::load_more_events_backwards`] .
635
635
#[ derive( Debug ) ]
636
636
pub ( super ) enum LoadMoreEventsBackwardsOutcome {
637
637
/// A gap has been inserted.
638
- Gap ,
638
+ Gap {
639
+ /// The previous batch token to be used as the "end" parameter in the
640
+ /// back-pagination request.
641
+ prev_token : Option < String > ,
642
+ } ,
639
643
640
644
/// The start of the timeline has been reached.
641
645
StartOfTimeline ,
@@ -646,6 +650,9 @@ pub(super) enum LoadMoreEventsBackwardsOutcome {
646
650
timeline_event_diffs : Vec < VectorDiff < TimelineEvent > > ,
647
651
reached_start : bool ,
648
652
} ,
653
+
654
+ /// The caller must wait for the initial previous-batch token, and retry.
655
+ WaitForInitialPrevToken ,
649
656
}
650
657
651
658
// Use a private module to hide `events` to this parent module.
@@ -811,79 +818,96 @@ mod private {
811
818
Ok ( ( deduplication_outcome, all_duplicates) )
812
819
}
813
820
821
+ /// Given a fully-loaded linked chunk with no gaps, return the
822
+ /// [`LoadMoreEventsBackwardsOutcome`] expected for this room's cache.
823
+ fn conclude_load_more_for_fully_loaded_chunk ( & mut self ) -> LoadMoreEventsBackwardsOutcome {
824
+ // If we never received events for this room, this means we've never
825
+ // received a sync for that room, because every room must have at least a
826
+ // room creation event. Otherwise, we have reached the start of the
827
+ // timeline.
828
+ if self . events . events ( ) . next ( ) . is_some ( ) {
829
+ // If there's at least one event, this means we've reached the start of the
830
+ // timeline, since the chunk is fully loaded.
831
+ LoadMoreEventsBackwardsOutcome :: StartOfTimeline
832
+ } else if !self . waited_for_initial_prev_token {
833
+ // There's no events. Since we haven't yet, wait for an initial previous-token.
834
+ LoadMoreEventsBackwardsOutcome :: WaitForInitialPrevToken
835
+ } else {
836
+ // Otherwise, we've already waited, *and* received no previous-batch token from
837
+ // the sync, *and* there are still no events in the fully-loaded
838
+ // chunk: start back-pagination from the end of the room.
839
+ LoadMoreEventsBackwardsOutcome :: Gap { prev_token : None }
840
+ }
841
+ }
842
+
814
843
/// Load more events backwards if the last chunk is **not** a gap.
815
- #[ must_use = "Updates as `VectorDiff` must probably be propagated via `RoomEventCacheUpdate`" ]
816
844
pub ( in super :: super ) async fn load_more_events_backwards (
817
845
& mut self ,
818
846
) -> Result < LoadMoreEventsBackwardsOutcome , EventCacheError > {
819
847
let Some ( store) = self . store . get ( ) else {
820
- // No store: no events to insert. Pretend the caller has to act as if a gap was
821
- // present.
822
- return Ok ( LoadMoreEventsBackwardsOutcome :: Gap ) ;
848
+ // No store to reload events from. Pretend the caller has to act as if a gap was
849
+ // present. Limited syncs will always clear and push a gap, in this mode.
850
+ // There's no lazy-loading.
851
+
852
+ // Look for a gap in the in-memory chunk, iterating in reverse so as to get the
853
+ // most recent one.
854
+ if let Some ( prev_token) = self . events . rgap ( ) . map ( |gap| gap. prev_token ) {
855
+ return Ok ( LoadMoreEventsBackwardsOutcome :: Gap {
856
+ prev_token : Some ( prev_token) ,
857
+ } ) ;
858
+ }
859
+
860
+ return Ok ( self . conclude_load_more_for_fully_loaded_chunk ( ) ) ;
823
861
} ;
824
862
825
863
// If any in-memory chunk is a gap, don't load more events, and let the caller
826
864
// resolve the gap.
827
- if self . events . chunks ( ) . any ( |chunk| chunk . is_gap ( ) ) {
828
- return Ok ( LoadMoreEventsBackwardsOutcome :: Gap ) ;
865
+ if let Some ( prev_token ) = self . events . rgap ( ) . map ( |gap| gap . prev_token ) {
866
+ return Ok ( LoadMoreEventsBackwardsOutcome :: Gap { prev_token : Some ( prev_token ) } ) ;
829
867
}
830
868
831
869
// Because `first_chunk` is `not `Send`, get this information before the
832
870
// `.await` point, so that this `Future` can implement `Send`.
833
871
let first_chunk_identifier =
834
872
self . events . chunks ( ) . next ( ) . expect ( "a linked chunk is never empty" ) . identifier ( ) ;
835
873
836
- let room_id = & self . room ;
837
874
let store = store. lock ( ) . await ?;
838
875
839
876
// The first chunk is not a gap, we can load its previous chunk.
840
877
let new_first_chunk =
841
- match store. load_previous_chunk ( room_id , first_chunk_identifier) . await {
878
+ match store. load_previous_chunk ( & self . room , first_chunk_identifier) . await {
842
879
Ok ( Some ( new_first_chunk) ) => {
843
880
// All good, let's continue with this chunk.
844
881
new_first_chunk
845
882
}
846
883
847
884
Ok ( None ) => {
848
- // No previous chunk: no events to insert. This means one of two things:
849
- // - either the linked chunk is at the start of the timeline,
850
- // - or we haven't received any back-pagination token yet, and we should
851
- // wait for one.
852
- if self . waited_for_initial_prev_token {
853
- return Ok ( LoadMoreEventsBackwardsOutcome :: StartOfTimeline ) ;
854
- }
855
- // If we haven't waited yet, we request to resolve the gap, once we get the
856
- // previous-batch token from sync.
857
- return Ok ( LoadMoreEventsBackwardsOutcome :: Gap ) ;
885
+ // There's no previous chunk. The chunk is now fully-loaded. Conclude.
886
+ return Ok ( self . conclude_load_more_for_fully_loaded_chunk ( ) ) ;
858
887
}
859
888
860
889
Err ( err) => {
861
890
error ! ( "error when loading the previous chunk of a linked chunk: {err}" ) ;
862
891
863
892
// Clear storage for this room.
864
- store. handle_linked_chunk_updates ( room_id , vec ! [ Update :: Clear ] ) . await ?;
893
+ store. handle_linked_chunk_updates ( & self . room , vec ! [ Update :: Clear ] ) . await ?;
865
894
866
895
// Return the error.
867
896
return Err ( err. into ( ) ) ;
868
897
}
869
898
} ;
870
899
871
- let events = match & new_first_chunk. content {
872
- ChunkContent :: Gap ( _) => None ,
873
- ChunkContent :: Items ( events) => {
874
- // We've reached the start on disk, if and only if, there was no chunk prior to
875
- // the one we just loaded.
876
- let reached_start = new_first_chunk. previous . is_none ( ) ;
900
+ let chunk_content = new_first_chunk. content . clone ( ) ;
877
901
878
- Some ( ( events . clone ( ) , reached_start ) )
879
- }
880
- } ;
902
+ // We've reached the start on disk, if and only if, there was no chunk prior to
903
+ // the one we just loaded.
904
+ let reached_start = new_first_chunk . previous . is_none ( ) ;
881
905
882
906
if let Err ( err) = self . events . insert_new_chunk_as_first ( new_first_chunk) {
883
907
error ! ( "error when inserting the previous chunk into its linked chunk: {err}" ) ;
884
908
885
909
// Clear storage for this room.
886
- store. handle_linked_chunk_updates ( room_id , vec ! [ Update :: Clear ] ) . await ?;
910
+ store. handle_linked_chunk_updates ( & self . room , vec ! [ Update :: Clear ] ) . await ?;
887
911
888
912
// Return the error.
889
913
return Err ( err. into ( ) ) ;
@@ -896,9 +920,12 @@ mod private {
896
920
// However, we want to get updates as `VectorDiff`s.
897
921
let timeline_event_diffs = self . events . updates_as_vector_diffs ( ) ;
898
922
899
- Ok ( match events {
900
- None => LoadMoreEventsBackwardsOutcome :: Gap ,
901
- Some ( ( events, reached_start) ) => LoadMoreEventsBackwardsOutcome :: Events {
923
+ Ok ( match chunk_content {
924
+ ChunkContent :: Gap ( gap) => {
925
+ LoadMoreEventsBackwardsOutcome :: Gap { prev_token : Some ( gap. prev_token ) }
926
+ }
927
+
928
+ ChunkContent :: Items ( events) => LoadMoreEventsBackwardsOutcome :: Events {
902
929
events,
903
930
timeline_event_diffs,
904
931
reached_start,
@@ -2027,7 +2054,7 @@ mod tests {
2027
2054
// But if I manually reload more of the chunk, the gap will be present.
2028
2055
assert_matches ! (
2029
2056
state. load_more_events_backwards( ) . await . unwrap( ) ,
2030
- LoadMoreEventsBackwardsOutcome :: Gap
2057
+ LoadMoreEventsBackwardsOutcome :: Gap { .. }
2031
2058
) ;
2032
2059
2033
2060
num_gaps = 0 ;
0 commit comments