diff --git a/src/cargo/util/dependency_queue.rs b/src/cargo/util/dependency_queue.rs index db8f535f495..94654950785 100644 --- a/src/cargo/util/dependency_queue.rs +++ b/src/cargo/util/dependency_queue.rs @@ -31,8 +31,8 @@ pub struct DependencyQueue { /// easily indexable with just an `N` reverse_dep_map: HashMap>>, - /// Topological depth of each key - depth: HashMap, + /// The total number of packages that are transitively waiting on this package + priority: HashMap, } impl Default for DependencyQueue { @@ -47,7 +47,7 @@ impl DependencyQueue { DependencyQueue { dep_map: HashMap::new(), reverse_dep_map: HashMap::new(), - depth: HashMap::new(), + priority: HashMap::new(), } } } @@ -82,36 +82,39 @@ impl DependencyQueue { /// All nodes have been added, calculate some internal metadata and prepare /// for `dequeue`. pub fn queue_finished(&mut self) { + let mut out = HashMap::new(); for key in self.dep_map.keys() { - depth(key, &self.reverse_dep_map, &mut self.depth); + depth(key, &self.reverse_dep_map, &mut out); } + self.priority = out.into_iter().map(|(n, set)| (n, set.len())).collect(); - fn depth( + fn depth<'a, N: Hash + Eq + Clone, E: Hash + Eq + Clone>( key: &N, map: &HashMap>>, - results: &mut HashMap, - ) -> usize { - const IN_PROGRESS: usize = !0; - - if let Some(&depth) = results.get(key) { - assert_ne!(depth, IN_PROGRESS, "cycle in DependencyQueue"); + results: &'a mut HashMap>, + ) -> &'a HashSet { + if results.contains_key(key) { + let depth = &results[key]; + assert!(!depth.is_empty(), "cycle in DependencyQueue"); return depth; } + results.insert(key.clone(), HashSet::new()); - results.insert(key.clone(), IN_PROGRESS); + let mut set = HashSet::new(); + set.insert(key.clone()); - let depth = 1 + map + for dep in map .get(key) .into_iter() .flat_map(|it| it.values()) .flat_map(|set| set) - .map(|dep| depth(dep, map, results)) - .max() - .unwrap_or(0); - - *results.get_mut(key).unwrap() = depth; + { + set.extend(depth(dep, map, results).iter().cloned()) + } - depth + let slot = results.get_mut(key).unwrap(); + *slot = set; + return &*slot; } } @@ -122,7 +125,7 @@ impl DependencyQueue { pub fn dequeue(&mut self) -> Option<(N, V)> { // Look at all our crates and find everything that's ready to build (no // deps). After we've got that candidate set select the one which has - // the maximum depth in the dependency graph. This way we should + // the maximum priority in the dependency graph. This way we should // hopefully keep CPUs hottest the longest by ensuring that long // dependency chains are scheduled early on in the build process and the // leafs higher in the tree can fill in the cracks later. @@ -135,7 +138,7 @@ impl DependencyQueue { .iter() .filter(|(_, (deps, _))| deps.is_empty()) .map(|(key, _)| key.clone()) - .max_by_key(|k| self.depth[k]); + .max_by_key(|k| self.priority[k]); let key = match next { Some(key) => key, None => return None,