Commit 0d900d49c1ac
tarball1 file changed+13-0
@@ -861,6 +861,9 @@ impl<'a> RoomEventCacheStateLockWriteGuard<'a> {
861861
}862862
let linked_chunk_id = LinkedChunkId::Room(&self.state.room_id);863863
let mut first = chunk.chunks().next().expect("a linked chunk is never empty").identifier();864
+ // a stored chain that loops back on itself would otherwise keep this walk, and the room865
+ // state lock it runs under, going forever, which stalls every room's sync handling866
+ let mut seen = HashSet::from([first]);864867
while let Some(previous) = self.store.load_previous_chunk(linked_chunk_id, first).await? {865868
if let ChunkContent::Items(events) = &previous.content866869
&& let Some(id) = events.iter().rev().find_map(Event::event_id)@@ -868,6 +871,15 @@ impl<'a> RoomEventCacheStateLockWriteGuard<'a> {
868871
return Ok(Some(id));869872
}870873
first = previous.identifier;874
+ if !seen.insert(first) {875
+ error!(room_id = %self.state.room_id, "stored linked chunk loops back on itself");876
+ return Err(EventCacheError::LinkedChunkLoader(877
+ lazy_loader::LazyLoaderError::Cycle {878
+ new_chunk: first,879
+ with_chunk: first,880
+ },881
+ ));882
+ }871883
}872884
Ok(None)873885
}@@ -1012,6 +1024,7 @@ impl<'a> RoomEventCacheStateLockWriteGuard<'a> {
10121024
mut timeline: Timeline,10131025
ephemeral_events: &[Raw<AnySyncEphemeralRoomEvent>],10141026
) -> Result<(bool, Vec<VectorDiff<Event>>), EventCacheError> {1027
+ debug!(room_id = %self.state.room_id, "handle_sync started");10151028
let mut prev_batch = timeline.prev_batch.take();10161029
let had_prev_batch = prev_batch.is_some();