diff --git a/changelog.d/2115.bugfix.md b/changelog.d/2115.bugfix.md new file mode 100644 index 000000000..351d69869 --- /dev/null +++ b/changelog.d/2115.bugfix.md @@ -0,0 +1 @@ +Events arriving after one of their children has already been backfilled are no longer used as forward extremities. Contributed by @eleboucher. diff --git a/src/service/rooms/event_handler/fetch_and_handle_outliers.rs b/src/service/rooms/event_handler/fetch_and_handle_outliers.rs index f8c56acf2..10a384727 100644 --- a/src/service/rooms/event_handler/fetch_and_handle_outliers.rs +++ b/src/service/rooms/event_handler/fetch_and_handle_outliers.rs @@ -154,9 +154,9 @@ pub async fn get_missing_events( .stream() .fold(0_u8, |i, event_id| async move { if self.services.timeline.pdu_exists(event_id).await { - i.expected_add(1) - } else { i + } else { + i.expected_add(1) } }) .await; diff --git a/src/service/rooms/timeline/append.rs b/src/service/rooms/timeline/append.rs index 05577af95..99c2bbc8c 100644 --- a/src/service/rooms/timeline/append.rs +++ b/src/service/rooms/timeline/append.rs @@ -194,7 +194,24 @@ async fn progress_state_and_extremities( }) .collect::>() .await; - forward_extremities.push(incoming_pdu.event_id().to_owned()); + + // An event with a child is not a leaf, but a room with no extremities cannot be + // written to, so it is added anyway when nothing else remains. + let has_child = self + .services + .pdu_metadata + .is_event_referenced(&incoming_pdu.room_id_or_hash(), incoming_pdu.event_id()) + .await; + if !has_child || forward_extremities.is_empty() { + if has_child { + warn!( + "Adding {} as an extremity despite its child, the room has no other leaves", + incoming_pdu.event_id() + ); + } + forward_extremities.push(incoming_pdu.event_id().to_owned()); + } + debug!( "Retained {} extremities checked against {} prev_events", forward_extremities.len(), diff --git a/src/service/rooms/timeline/backfill.rs b/src/service/rooms/timeline/backfill.rs index 36b854a67..28c9c4949 100644 --- a/src/service/rooms/timeline/backfill.rs +++ b/src/service/rooms/timeline/backfill.rs @@ -213,6 +213,12 @@ pub async fn backfill_pdu(&self, origin: &ServerName, pdu: Box) -> drop(insert_lock); + // Backfilled events skip append_pdu, so this is the only place their + // prev_events can be marked as referenced. See issue #2115. + self.services + .pdu_metadata + .mark_as_referenced(&room_id, pdu.prev_events().map(AsRef::as_ref)); + if pdu.kind == TimelineEventType::RoomMessage { let content: ExtractBody = pdu.get_content()?; if let Some(body) = content.body {