extract the depends_on helper function

Make `add_edge` infallible
This commit is contained in:
Niko Matsakis 2021-10-27 08:27:09 -04:00
parent e870d02da1
commit ec38398991
2 changed files with 40 additions and 26 deletions

View file

@ -418,15 +418,22 @@ impl Runtime {
/// Try to make this runtime blocked on `other_id`. Returns true
/// upon success or false if `other_id` is already blocked on us.
pub(crate) fn try_block_on(&self, database_key: DatabaseKeyIndex, other_id: RuntimeId) -> bool {
self.shared_state.dependency_graph.lock().add_edge(
self.id(),
database_key,
other_id,
self.local_state
.borrow_query_stack()
.iter()
.map(|query| query.database_key_index),
)
let mut dg = self.shared_state.dependency_graph.lock();
if dg.depends_on(other_id, self.id()) {
false
} else {
dg.add_edge(
self.id(),
database_key,
other_id,
self.local_state
.borrow_query_stack()
.iter()
.map(|query| query.database_key_index),
);
true
}
}
pub(crate) fn unblock_queries_blocked_on_self(&self, database_key_index: DatabaseKeyIndex) {

View file

@ -28,27 +28,35 @@ impl Default for DependencyGraph {
}
impl DependencyGraph {
/// Attempt to add an edge `from_id -> to_id` into the result graph.
/// True if `from_id` depends on `to_id`.
///
/// (i.e., there is a path from `from_id` to `to_id` in the graph.)
pub(super) fn depends_on(&mut self, from_id: RuntimeId, to_id: RuntimeId) -> bool {
let mut p = from_id;
while let Some(q) = self.edges.get(&p).map(|edge| edge.id) {
if q == to_id {
return true;
}
p = q;
}
false
}
/// Attempt to add an edge `from_id -> to_id` into the result graph,
/// meaning that `from_id` is blocked on `to_id`.
///
/// Precondition: No path from `to_id` to `from_id`.
pub(super) fn add_edge(
&mut self,
from_id: RuntimeId,
database_key: DatabaseKeyIndex,
to_id: RuntimeId,
path: impl IntoIterator<Item = DatabaseKeyIndex>,
) -> bool {
) {
assert_ne!(from_id, to_id);
debug_assert!(!self.edges.contains_key(&from_id));
// First: walk the chain of things that `to_id` depends on,
// looking for us.
let mut p = to_id;
while let Some(q) = self.edges.get(&p).map(|edge| edge.id) {
if q == from_id {
return false;
}
p = q;
}
debug_assert!(!self.depends_on(to_id, from_id));
self.edges.insert(
from_id,
@ -61,7 +69,6 @@ impl DependencyGraph {
.entry(database_key.clone())
.or_default()
.push(from_id);
true
}
pub(super) fn remove_edge(&mut self, database_key: DatabaseKeyIndex, to_id: RuntimeId) {
@ -138,7 +145,7 @@ mod tests {
let mut graph = DependencyGraph::default();
let a = RuntimeId { counter: 0 };
let b = RuntimeId { counter: 1 };
assert!(graph.add_edge(a, dki(2), b, dkivec![1]));
graph.add_edge(a, dki(2), b, dkivec![1]);
let mut v = vec![];
graph.push_cycle_path(dki(1), a, dkivec![3, 2], &mut v);
assert_eq!(v, vec![dki(1), dki(2)]);
@ -150,8 +157,8 @@ mod tests {
let a = RuntimeId { counter: 0 };
let b = RuntimeId { counter: 1 };
let c = RuntimeId { counter: 2 };
assert!(graph.add_edge(a, dki(3), b, dkivec![1]));
assert!(graph.add_edge(b, dki(4), c, dkivec![2, 3]));
graph.add_edge(a, dki(3), b, dkivec![1]);
graph.add_edge(b, dki(4), c, dkivec![2, 3]);
// assert!(graph.add_edge(c, &1, a, vec![5, 6, 4, 7]));
let mut v = vec![];
graph.push_cycle_path(dki(1), a, dkivec![5, 6, 4, 7], &mut v);