refactor(#2500): encapsulate the jobq lock, drop the dead borrowed-guard layer
Make the resource lock unmisusable from outside the crate: the public surface is now purely declarative (build a Graph with Dep::Resource edges, configure capacities, run the Scheduler), and the scheduler owns every acquire/release — a consumer never holds a guard, so it cannot hold the lock wrong. - `guard` module + `ResourceTable::try_acquire_all`/`release_all` + `Graph::set_state` are now `pub(crate)`. - Remove the dead borrowed-guard layer (`ResourceGuard::borrowed`, `Acq::Borrowed`, `is_owning`): the scheduler tracks re-entrancy via its own single borrow slot per (holder, resource) and never constructs a borrowed guard, so re-entrancy lives in exactly one place. `Acq` collapses into the owning `ResourceGuard` struct. - `#[must_use]` on `Scheduler::settle` — ignoring its ids silently drops runnable work. - `SharedResources::with` (test-only table observability) is `#[cfg(test)]`. - Drop the moot borrowed-guard tests; retained owning tests are black-box, and the redundant `set_state` test helper is gone.
This commit is contained in:
parent
b4bcf8b6e4
commit
f64ab47de0
4 changed files with 41 additions and 111 deletions
|
|
@ -27,9 +27,9 @@
|
|||
//! completion via guard objects, recursive within a group.
|
||||
//!
|
||||
//! The [`scheduler`] settle loop drives execution; the resource machinery
|
||||
//! lives in [`resources`] and the RAII lock guards over it in [`guard`].
|
||||
//! lives in [`resources`] and the RAII lock guards over it in `guard`.
|
||||
|
||||
pub mod guard;
|
||||
pub(crate) mod guard;
|
||||
pub mod resources;
|
||||
pub mod scheduler;
|
||||
|
||||
|
|
@ -298,7 +298,7 @@ impl<N, R> Graph<N, R> {
|
|||
/// Set a node's lifecycle state, returning `false` for an unknown id. The
|
||||
/// scheduler drives every state transition — nothing else mutates state,
|
||||
/// which is what keeps the resource guards + terminality in sync.
|
||||
pub fn set_state(&mut self, id: NodeId, state: State) -> bool {
|
||||
pub(crate) fn set_state(&mut self, id: NodeId, state: State) -> bool {
|
||||
if let Some(node) = self.nodes.iter_mut().find(|n| n.id == id) {
|
||||
node.state = state;
|
||||
true
|
||||
|
|
@ -381,11 +381,6 @@ mod tests {
|
|||
assert_eq!(g.node(a).unwrap().parent, None);
|
||||
}
|
||||
|
||||
fn set_state<N, R>(g: &mut Graph<N, R>, id: NodeId, state: State) {
|
||||
let idx = g.nodes.iter().position(|n| n.id == id).unwrap();
|
||||
g.nodes[idx].state = state;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn group_terminal_requires_the_group_node_and_all_children_terminal() {
|
||||
let mut g: Graph<&str, String> = Graph::new();
|
||||
|
|
@ -395,10 +390,10 @@ mod tests {
|
|||
assert!(!g.group_terminal(group));
|
||||
// Child done, but the group node itself is still pending → NOT terminal:
|
||||
// the group node's own state is load-bearing, not just its children.
|
||||
set_state(&mut g, child, State::Done);
|
||||
g.set_state(child, State::Done);
|
||||
assert!(!g.group_terminal(group));
|
||||
// Group node terminal too → the whole group is terminal.
|
||||
set_state(&mut g, group, State::Done);
|
||||
g.set_state(group, State::Done);
|
||||
assert!(g.group_terminal(group));
|
||||
}
|
||||
|
||||
|
|
@ -408,10 +403,10 @@ mod tests {
|
|||
// not read as terminal just because its child set is currently empty.
|
||||
let mut g: Graph<&str, String> = Graph::new();
|
||||
let group = g.insert("group", vec![], None).unwrap();
|
||||
set_state(&mut g, group, State::Running);
|
||||
g.set_state(group, State::Running);
|
||||
assert!(!g.group_terminal(group));
|
||||
// Once it finishes (having grown no children), it is terminal.
|
||||
set_state(&mut g, group, State::Done);
|
||||
g.set_state(group, State::Done);
|
||||
assert!(g.group_terminal(group));
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue