atagen

matrix-rust-sdk

public
Star0
Watch0

Commit 17b53943be2d

tarball

atagen <boss@atagen.co>2026-10-25 10:26 UTC

2 files changed+43-27
timeline: fence history flushes on the subscriber task instead of replacing

flush_history ran wait_for_history and then replace_with_initial_history, so every flush rebuilt the timeline and dropped read receipts and item ids although commit_history_candidate already broadcasts incremental diffs. The subscriber task now drains what is queued after wait_for_history through handle_history_update before replying, which orders the fence with the updates it covers, and only a Lagged receiver still replaces.
Modified file: crates/matrix-sdk-ui/src/timeline/mod.rs+5 additions−1 deletions
@@ -227,7 +227,11 @@ pub struct AttachmentConfig {
227227 }
228228
229229 impl Timeline {
230- #[doc = "Wait until this live timeline has applied all history currently retained by its room cache."]
230+ /// Wait for earlier history operations on the room cache, then until this
231+ /// live timeline has applied every update they published.
232+ ///
233+ /// Updates apply incrementally, keeping read receipts and item ids, and
234+ /// only a lagged subscriber falls back to replacing the timeline.
231235 pub async fn flush_history(&self) -> Result<(), Error> {
232236 let Some(flush) = &self.history_flush else {
233237 return Ok(());
Modified file: crates/matrix-sdk-ui/src/timeline/tasks.rs+38 additions−26 deletions
@@ -25,7 +25,10 @@ use matrix_sdk::{
2525 send_queue::RoomSendQueueUpdate,
2626 };
2727 use ruma::OwnedEventId;
28-use tokio::sync::broadcast::{Receiver, error::RecvError};
28+use tokio::sync::broadcast::{
29+ Receiver,
30+ error::{RecvError, TryRecvError},
31+};
2932 use tokio::sync::{mpsc, oneshot};
3033 use tracing::{error, instrument, trace, warn};
3134
@@ -213,39 +216,48 @@ pub(in crate::timeline) async fn room_event_cache_updates_task(
213216 ) {
214217 trace!("Spawned the event subscriber task.");
215218
219+ let mut flushing: Option<oneshot::Sender<Result<(), crate::timeline::Error>>> = None;
220+
216221 loop {
217222 trace!("Waiting for an event.");
218223
219- let update = tokio::select! {
220- request = async {
221- match history_flush_requests.as_mut() {
222- Some(requests) => requests.recv().await,
223- None => std::future::pending::<Option<oneshot::Sender<Result<(), crate::timeline::Error>>>>().await,
224+ let update = if let Some(reply) = flushing.take() {
225+ match room_event_cache_subscriber.try_recv() {
226+ Ok(update) => {
227+ flushing = Some(reply);
228+ Ok(update)
229+ }
230+ Err(TryRecvError::Empty) => {
231+ let _ = reply.send(Ok(()));
232+ continue;
224233 }
225- } => {
226- if let Some(reply) = request {
227- if let Err(error) = room_event_cache.wait_for_history().await {
228- let _ = reply.send(Err(error.into()));
229- continue;
234+ Err(TryRecvError::Lagged(num_skipped)) => {
235+ flushing = Some(reply);
236+ Err(RecvError::Lagged(num_skipped))
237+ }
238+ Err(TryRecvError::Closed) => break,
239+ }
240+ } else {
241+ tokio::select! {
242+ request = async {
243+ match history_flush_requests.as_mut() {
244+ Some(requests) => requests.recv().await,
245+ None => std::future::pending().await,
230246 }
231- match room_event_cache.subscribe_with_history().await {
232- Ok((initial_events, gaps, subscriber)) => {
233- room_event_cache_subscriber = subscriber;
234- timeline_controller
235- .replace_with_initial_history(initial_events, gaps, RemoteEventOrigin::Cache)
236- .await;
237- let _ = reply.send(Ok(()));
238- }
239- Err(error) => {
240- let _ = reply.send(Err(error.into()));
241- }
247+ } => {
248+ match request {
249+ Some(reply) => match room_event_cache.wait_for_history().await {
250+ Ok(()) => flushing = Some(reply),
251+ Err(error) => {
252+ let _ = reply.send(Err(error.into()));
253+ }
254+ },
255+ None => history_flush_requests = None,
242256 }
243- } else {
244- history_flush_requests = None;
257+ continue;
245258 }
246- continue;
259+ update = room_event_cache_subscriber.recv() => update,
247260 }
248- update = room_event_cache_subscriber.recv() => update,
249261 };
250262 let update = match update {
251263 Ok(up) => up,