fix: Correctly handle still-missing state, always fetch full state atomically if regular fetch fails

This commit is contained in:
timedout committed 2026-06-20 17:08:00 +01:00
1 parent c28ea44e11
commit a945a4b2ad
3 files changed
+21 -8

No files matched your search

@@ -424,7 +424,12 @@ impl super::Service {
} }
let attempts = seen.get(&*next_id).copied().unwrap_or_default(); let attempts = seen.get(&*next_id).copied().unwrap_or_default();
if attempts >= 5 { if attempts >= 5 {
debug_error!(elapsed=?start.elapsed(),%attempts, %next_id, "Could not fetch missing event after 5 attempts, giving up"); debug_error!(
elapsed=?start.elapsed(),
%attempts,
%next_id,
"Could not fetch missing event after 5 attempts, giving up"
);
continue; continue;
} }
+10 -6
View File
@@ -145,7 +145,7 @@ impl super::Service {
); );
self.fetch_and_handle_missing_events( self.fetch_and_handle_missing_events(
origin, origin,
to_fetch, res.pdu_ids.clone(),
create_event, create_event,
room_id, room_id,
) )
@@ -161,7 +161,7 @@ impl super::Service {
); );
self.fetch_and_handle_missing_events( self.fetch_and_handle_missing_events(
origin, origin,
to_fetch, res.pdu_ids.clone(),
create_event, create_event,
room_id, room_id,
) )
@@ -192,6 +192,11 @@ impl super::Service {
}) })
.collect() .collect()
.await; .await;
assert!(
!state_events.is_empty(),
"Only missing {} events but read-ahead state vec was empty",
to_fetch.len()
);
debug!( debug!(
elapsed=?start.elapsed(), elapsed=?start.elapsed(),
to_fetch = to_fetch.len(), to_fetch = to_fetch.len(),
@@ -200,13 +205,12 @@ impl super::Service {
let fetched_state = self let fetched_state = self
.fetch_and_handle_missing_events(origin, to_fetch, create_event, room_id) .fetch_and_handle_missing_events(origin, to_fetch, create_event, room_id)
.await; .await;
assert!(
!fetched_state.is_empty(),
"fetch_and_handle_missing_events returned empty state map"
);
state_events.extend(fetched_state); state_events.extend(fetched_state);
} }
} }
if state_events.is_empty() {
return Ok(Some(HashMap::new()));
}
let mut state: HashMap<ShortStateKey, OwnedEventId> = let mut state: HashMap<ShortStateKey, OwnedEventId> =
HashMap::with_capacity(state_events.len()); HashMap::with_capacity(state_events.len());
@@ -93,7 +93,11 @@ pub(super) async fn upgrade_outlier_to_timeline_pdu(
if state_at_incoming_event.is_empty() if state_at_incoming_event.is_empty()
&& *incoming_pdu.event_type() != StateEventType::RoomCreate.into() && *incoming_pdu.event_type() != StateEventType::RoomCreate.into()
{ {
return Err!(Request(Forbidden("Incoming event has empty incoming state at"))); // This can happen if the remote sends an event but cannot be reached to fetch
// the state at it, and all other servers in the room (which might just be the
// unreachable server) are unable to provide required info.
// returning an error here allows the upgrade to be attempted at another time.
return Err!(Request(Forbidden("Could not resolve incoming state at event")));
} }
trace!(state_events = state_at_incoming_event.len(), "Calculated incoming state"); trace!(state_events = state_at_incoming_event.len(), "Calculated incoming state");