Commit 090dac278176
tarball2 files changed+85-8
@@ -2003,6 +2003,67 @@ mod timed_tests {
20032003
}20042004
20052005
#[async_test]2006
+ async fn test_limited_sync_after_shrink_to_a_gap_keeps_its_discontinuity() {2007
+ let room_id = room_id!("!shrunk-history:saucisse.bzh");2008
+ let client = MockClientBuilder::new(None).build().await;2009
+ let event_cache = client.event_cache();2010
+ event_cache.subscribe().unwrap();2011
+ client.base_client().get_or_create_room(room_id, RoomState::Joined);2012
+ let room = client.get_room(room_id).unwrap();2013
+ let (room_event_cache, _drop_handles) = room.event_cache().await.unwrap();2014
+ let f = EventFactory::new().room(room_id).sender(*ALICE);2015
+ let old_id = event_id!("$shrunk-old");2016
+ let new_id = event_id!("$shrunk-new");2017
+2018
+ room_event_cache2019
+ .handle_joined_room_update(JoinedRoomUpdate {2020
+ timeline: Timeline {2021
+ events: vec![f.text_msg("old").event_id(old_id).into_event()],2022
+ ..Default::default()2023
+ },2024
+ ..Default::default()2025
+ })2026
+ .await2027
+ .unwrap();2028
+ room_event_cache2029
+ .handle_joined_room_update(JoinedRoomUpdate {2030
+ timeline: Timeline {2031
+ limited: true,2032
+ prev_batch: Some("empty".to_owned()),2033
+ events: Vec::new(),2034
+ },2035
+ ..Default::default()2036
+ })2037
+ .await2038
+ .unwrap();2039
+ assert!(room_event_cache.events().await.unwrap().is_empty());2040
+ room_event_cache2041
+ .handle_joined_room_update(JoinedRoomUpdate {2042
+ timeline: Timeline {2043
+ limited: true,2044
+ prev_batch: Some("new".to_owned()),2045
+ events: vec![f.text_msg("new").event_id(new_id).into_event()],2046
+ },2047
+ ..Default::default()2048
+ })2049
+ .await2050
+ .unwrap();2051
+2052
+ let state = room_event_cache.inner.state.write().await.unwrap();2053
+ let candidate = state.history_candidate().await.unwrap();2054
+ let gaps: Vec<_> = candidate2055
+ .chunks()2056
+ .filter_map(|chunk| match chunk.content() {2057
+ ChunkContent::Gap(gap) => gap.history.clone(),2058
+ ChunkContent::Items(_) => None,2059
+ })2060
+ .collect();2061
+ assert_eq!(gaps.len(), 1);2062
+ assert_eq!(gaps[0].older_boundary.as_deref(), Some(old_id));2063
+ assert_eq!(gaps[0].newer_boundary.as_deref(), Some(new_id));2064
+ }2065
+2066
+ #[async_test]20062067
async fn test_auto_shrink_after_all_subscribers_are_gone() {20072068
let room_id = room_id!("!galette:saucisse.bzh");20082069
@@ -30,7 +30,8 @@ use matrix_sdk_base::{
3030
store::{EventCacheStoreLock, EventCacheStoreLockGuard, EventCacheStoreLockState},3131
},3232
linked_chunk::{33
- ChunkIdentifierGenerator, ChunkMetadata, LinkedChunkId, OwnedLinkedChunkId, Position,33
+ ChunkContent, ChunkIdentifierGenerator, ChunkMetadata, LinkedChunkId, OwnedLinkedChunkId,34
+ Position,3435
Update, lazy_loader,3536
},3637
serde_helpers::{extract_edit_target, extract_thread_root},@@ -828,6 +829,25 @@ impl<'a> RoomEventCacheStateLockWriteGuard<'a> {
828829
super::history::gap_positions(&self.state.room_linked_chunk)829830
}830831
832
+ /// Memory can hold no events at all, after a shrink to a trailing gap.833
+ async fn newest_retained_event_id(&self) -> Result<Option<OwnedEventId>, EventCacheError> {834
+ let chunk = &self.state.room_linked_chunk;835
+ if let Some(id) = chunk.revents().find_map(|(_, event)| event.event_id()) {836
+ return Ok(Some(id));837
+ }838
+ let linked_chunk_id = LinkedChunkId::Room(&self.state.room_id);839
+ let mut first = chunk.chunks().next().expect("a linked chunk is never empty").identifier();840
+ while let Some(previous) = self.store.load_previous_chunk(linked_chunk_id, first).await? {841
+ if let ChunkContent::Items(events) = &previous.content842
+ && let Some(id) = events.iter().rev().find_map(Event::event_id)843
+ {844
+ return Ok(Some(id));845
+ }846
+ first = previous.identifier;847
+ }848
+ Ok(None)849
+ }850
+831851
pub(super) async fn commit_history_candidate(832852
&mut self,833853
mut candidate: EventLinkedChunk,@@ -940,16 +960,12 @@ impl<'a> RoomEventCacheStateLockWriteGuard<'a> {
940960
// previous-batch token would only result in fetching other events we941961
// knew about. This is slightly incorrect in the presence of942962
// network splits, but this has shown to be Good Enough™.943
- if !timeline.limited && self.state.room_linked_chunk.events().next().is_some()944
- || all_duplicates945
- {963
+ let newest_retained = self.newest_retained_event_id().await?;964
+ if !timeline.limited && newest_retained.is_some() || all_duplicates {946965
prev_batch = None;947966
}948967
949
- let older_boundary = timeline950
- .limited951
- .then(|| self.state.room_linked_chunk.revents().find_map(|(_, event)| event.event_id()))952
- .flatten();968
+ let older_boundary = timeline.limited.then_some(newest_retained).flatten();953969
let newer_boundary =954970
timeline.limited.then(|| events.iter().find_map(Event::event_id)).flatten();955971
if older_boundary.is_some() && events.iter().any(|event| event.event_id() == older_boundary)