8000 fix(ot): fix some progress ops not being cleared by twitchyliquid64 · Pull Request #607 · gominimal/minimal · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8000
3 changes: 3 additions & 0 deletions crates/check/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,7 @@ async fn check_package(
let ctx = ctx.clone();
let pkg = pkg.clone();
let span = tracing::Span::current();
let check_op = check_op.clone();

tokio::task::spawn_blocking(move || {
let _enter = span.enter();
Expand Down Expand Up @@ -616,6 +617,8 @@ async fn check_package(

out.extend(file_based_results);

check_op.set_done();

Ok(out)
}

Expand Down
52 changes: 52 additions & 0 deletions crates/ot/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,21 @@ impl TrackerInner {
}
}

impl Drop for TrackerInner {
/// A node disappearing is itself a change the renderer must observe: it has
/// to re-snapshot and drop the bar for any operation whose node was dropped
/// without an explicit [`set_done`](OpTracker::set_done) — e.g. an early `?`
/// return, or a completed operation that simply went out of scope. The
/// renderer only repaints on a version bump, so without this wake an
/// orphaned spinner would keep animating (via indicatif's steady-tick
/// thread) until some unrelated mutation happened to wake it. `shared`
/// outlives this body — it is a field, dropped only after `drop` returns —
/// so the bump is sound.
fn drop(&mut self) {
self.shared.bump();
}
}

/// A node in the operation tree, potentially describing an operation.
///
/// Nodes may have a parent (unless they are the root) or children.
Expand Down Expand Up @@ -550,6 +565,43 @@ mod tests {
assert_eq!(r2.version(), 0, "mutating one tree must not touch another");
}

#[test]
fn dropping_a_node_bumps_version() {
// A node vanishing is a change a renderer must see (to clear its bar),
// even when the operation was never explicitly marked done.
let root = OpTracker::new_root();
let child = root.new_child();
child.set_op(Operation::ExtractPkg { name: "p".into() });
let before = root.version();
drop(child);
assert!(
root.version() > before,
"dropping a node must bump the version"
);
}

#[tokio::test]
async fn changed_wakes_on_node_drop() {
// The renderer only repaints on a wake; dropping an op node without
// set_done() must still wake it so it can clear the orphaned bar.
let root = OpTracker::new_root();
let child = root.new_child();
child.set_op(Operation::Check {
kind: CheckKind::CheckPackages,
name: "p".into(),
});
let mut rx = root.subscribe();
rx.borrow_and_update();
let h = tokio::spawn(async move { rx.changed().await });
tokio::task::yield_now().await;
drop(child);
tokio::time::timeout(Duration::from_secs(1), h)
.await
.expect("changed() should wake on node drop")
.expect("waiter task should not panic")
.expect("watch sender should be alive");
}

#[tokio::test]
async fn changed_wakes_on_mutation() {
let root = OpTracker::new_root();
Expand Down
2 changes: 2 additions & 0 deletions crates/rcache/src/remote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,8 @@ impl<B: FetchBackend> RemoteCache<B> {
)
.map_err(Error::ArchiveError)?;

materialize_op.set_done();

Ok((Instant::now().duration_since(start), cache_hnd))
}
}
Expand Down
0