diff --git a/crates/notebook/src/background.rs b/crates/notebook/src/background.rs index 3c38eae5c1bb4957f896617a9741f5c73dc76fc8..ea43b8477df8bcb5e6a42dc5c30a5fa6afc3b96e 100644 --- a/crates/notebook/src/background.rs +++ b/crates/notebook/src/background.rs @@ -284,7 +284,7 @@ impl Background { news |= match outcome { Ok((stamp, moved)) => { watch.stamp = Some(stamp); - watch.due = now + interval; + watch.due = watch.due.min(now + interval); if moved { changed.push(path); } @@ -299,7 +299,7 @@ impl Background { moved || before != summary(&watch.status) } Err(error) => { - watch.due = now + RETRY; + watch.due = watch.due.min(now + RETRY); watch.fail(&error, queued) } }; @@ -846,6 +846,8 @@ impl Watched { watch.due = now + interval; continue; } + // Anything asking for the section during the check can only bring this forward. + watch.due = now + interval.max(RETRY); return Next::Check { path: watch.path.clone(), replica: watch.replica.clone(), @@ -1200,7 +1202,7 @@ mod tests { .find(|watch| watch.path == path) .unwrap(); watch.current = false; - watch.due = now + interval; + watch.due = watch.due.min(now + interval); checks.push((now, path, !current)); } } @@ -1468,6 +1470,45 @@ mod tests { drop(rewatch); } + #[test] + fn a_section_released_during_its_check_is_checked_again_at_once() { + let (sender, stamps) = mpsc::channel(); + let files = Files { + images: Arc::default(), + stamps: sender, + }; + let section = path(0); + files.write( + §ion, + onestore::create_section("s.one", §ion, "Author").unwrap(), + ); + let (armed, watches) = mpsc::channel(); + let remote = files.clone(); + let background = Background::start( + false, + move |reports| { + armed.send(reports).unwrap(); + let (files, listed) = (remote.clone(), remote.clone()); + let bind = move |path: &str| File(files.clone(), path.to_owned()); + let list = move |folder: String| std::future::ready(Ok(listed.list(&folder))); + Ok(((bind, list), true)) + }, + || {}, + ) + .unwrap(); + background.watch(vec![files.known(§ion)]); + let watch = watches.recv().unwrap(); + assert!(quiet(&stamps, SETTLE).is_empty()); + // Holding the files parks the check reported next inside its stamp read. + let parked = files.images.lock().unwrap(); + watch.touched(std::slice::from_ref(§ion)); + assert_eq!(stamps.recv_timeout(SETTLE * 2).unwrap(), section); + background.0.released(§ion); + drop(parked); + assert_eq!(stamps.recv_timeout(SETTLE).unwrap(), section); + drop(background); + } + #[test] fn held_status_tracks_its_worker_without_retaining_the_replica() { use crate::session::SyncState;