refactor(#2949): claim_one is the primitive, settle is it in a loop
One-at-a-time claiming is what lets a caller choose between claiming again immediately and backing off — a batch return cannot express that choice, and the choice is the point: the run loop wants to know there was work before it decides whether to wait. `settle()` keeps its exact meaning as `while let Some(id) = claim_one()`. A node started by an earlier iteration is `Running`, not terminal, so it cannot satisfy another node's dependency in the same sweep; it only consumes resources. The crate's ~45 existing `settle()` assertions — which cover resource borrowing, cap-1 serialisation, roll-up and cancellation — are what verify that equivalence, so it is checked rather than argued. `None` means "nothing runnable right now", which is deliberately a different statement from "nothing pending": a node can be pending and unrunnable because its resources are held elsewhere. Cost stated rather than left to be found: each `claim_one` rescans the pending set, so `settle` is O(n^2) in nodes claimed where the single-pass version was O(n). The graph is bounded by history retention.
This commit is contained in:
parent
77cc7bea6b
commit
9e91bf7813
1 changed files with 27 additions and 10 deletions
|
|
@ -138,25 +138,42 @@ impl<N, R: Clone + Eq + Hash> Scheduler<N, R> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Claim every currently-runnable pending node and start it: node-deps
|
/// Claim **one** currently-runnable pending node and start it: node-deps
|
||||||
/// satisfied and all resource-deps acquired atomically (all-or-nothing).
|
/// satisfied and all resource-deps acquired atomically (all-or-nothing).
|
||||||
/// Each claimed node is marked `Running`, its acquired units recorded, and
|
/// The node is marked `Running`, its acquired units recorded, and its id
|
||||||
/// its id returned for the runner to execute. A single pass suffices — a
|
/// returned for the caller to execute. `None` means nothing is runnable
|
||||||
/// node started here is `Running`, not terminal, so it cannot satisfy another
|
/// right now — which is a different statement from "nothing is pending".
|
||||||
/// node's dependency in the same pass; it only consumes resources.
|
///
|
||||||
|
/// One-at-a-time is the primitive on purpose: it lets the caller decide
|
||||||
|
/// between claiming again immediately and backing off, a choice a batch
|
||||||
|
/// return can't express. [`Self::settle`] is this in a loop.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn settle(&mut self) -> Vec<NodeId> {
|
pub fn claim_one(&mut self) -> Option<NodeId> {
|
||||||
let pending: Vec<NodeId> = self
|
let pending: Vec<NodeId> = self
|
||||||
.graph
|
.graph
|
||||||
.nodes()
|
.nodes()
|
||||||
.filter(|n| n.state == State::Pending)
|
.filter(|n| n.state == State::Pending)
|
||||||
.map(|n| n.id)
|
.map(|n| n.id)
|
||||||
.collect();
|
.collect();
|
||||||
|
pending
|
||||||
|
.into_iter()
|
||||||
|
.find(|&id| self.node_deps_satisfied(id) && self.try_start(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Claim every currently-runnable pending node. Equivalent to calling
|
||||||
|
/// [`Self::claim_one`] until it yields `None`: a node started by an earlier
|
||||||
|
/// iteration is `Running`, not terminal, so it cannot satisfy another
|
||||||
|
/// node's dependency here — it only consumes resources.
|
||||||
|
///
|
||||||
|
/// ⚠️ Each iteration rescans the pending set, so this is O(n²) in the
|
||||||
|
/// number of nodes claimed where the old single-pass version was O(n). The
|
||||||
|
/// graph is bounded by history retention, so that is affordable; it is
|
||||||
|
/// stated rather than left to be discovered.
|
||||||
|
#[must_use]
|
||||||
|
pub fn settle(&mut self) -> Vec<NodeId> {
|
||||||
let mut started = Vec::new();
|
let mut started = Vec::new();
|
||||||
for id in pending {
|
while let Some(id) = self.claim_one() {
|
||||||
if self.node_deps_satisfied(id) && self.try_start(id) {
|
started.push(id);
|
||||||
started.push(id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
started
|
started
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue