From a7846b842c20bae9d38fed0563def11be97717b2 Mon Sep 17 00:00:00 2001 From: Eh2406 Date: Sat, 3 Mar 2018 10:56:57 -0500 Subject: [PATCH] Make a `RegistryQueryer` to own the cache --- src/cargo/core/resolver/mod.rs | 203 ++++++++++++++++++--------------- 1 file changed, 108 insertions(+), 95 deletions(-) diff --git a/src/cargo/core/resolver/mod.rs b/src/cargo/core/resolver/mod.rs index 44e9124d5..c169121a3 100644 --- a/src/cargo/core/resolver/mod.rs +++ b/src/cargo/core/resolver/mod.rs @@ -364,7 +364,7 @@ pub fn resolve(summaries: &[(Summary, Method)], warnings: RcList::new(), }; let _p = profile::start("resolving"); - let cx = activate_deps_loop(cx, registry, summaries, config)?; + let cx = activate_deps_loop(cx, &mut RegistryQueryer::new(registry, replacements), summaries, config)?; let mut resolve = Resolve { graph: cx.graph(), @@ -410,7 +410,7 @@ pub fn resolve(summaries: &[(Summary, Method)], /// If `candidate` was activated, this function returns the dependency frame to /// iterate through next. fn activate(cx: &mut Context, - registry: &mut Registry, + registry: &mut RegistryQueryer, parent: Option<&Summary>, candidate: Candidate, method: &Method) @@ -573,6 +573,108 @@ impl ConflictReason { } } +struct RegistryQueryer<'a> { + registry: &'a mut (Registry + 'a), + replacements: &'a [(PackageIdSpec, Dependency)], + // TODO: with nll the Rc can be removed + cache: BTreeMap>>, +} + +impl<'a> RegistryQueryer<'a> { + fn new(registry: &'a mut Registry, replacements: &'a [(PackageIdSpec, Dependency)],) -> Self { + RegistryQueryer { + registry, + replacements, + cache: BTreeMap::new(), + } + } + + /// Queries the `registry` to return a list of candidates for `dep`. + /// + /// This method is the location where overrides are taken into account. If + /// any candidates are returned which match an override then the override is + /// applied by performing a second query for what the override should + /// return. + fn query(&mut self, dep: &Dependency) -> CargoResult>> { + if let Some(out) = self.cache.get(dep).cloned() { + return Ok(out); + } + + let mut ret = Vec::new(); + self.registry.query(dep, &mut |s| { + ret.push(Candidate { summary: s, replace: None }); + })?; + for candidate in ret.iter_mut() { + let summary = &candidate.summary; + + let mut potential_matches = self.replacements.iter() + .filter(|&&(ref spec, _)| spec.matches(summary.package_id())); + + let &(ref spec, ref dep) = match potential_matches.next() { + None => continue, + Some(replacement) => replacement, + }; + debug!("found an override for {} {}", dep.name(), dep.version_req()); + + let mut summaries = self.registry.query_vec(dep)?.into_iter(); + let s = summaries.next().ok_or_else(|| { + format_err!("no matching package for override `{}` found\n\ + location searched: {}\n\ + version required: {}", + spec, dep.source_id(), dep.version_req()) + })?; + let summaries = summaries.collect::>(); + if !summaries.is_empty() { + let bullets = summaries.iter().map(|s| { + format!(" * {}", s.package_id()) + }).collect::>(); + bail!("the replacement specification `{}` matched \ + multiple packages:\n * {}\n{}", spec, s.package_id(), + bullets.join("\n")); + } + + // The dependency should be hard-coded to have the same name and an + // exact version requirement, so both of these assertions should + // never fail. + assert_eq!(s.version(), summary.version()); + assert_eq!(s.name(), summary.name()); + + let replace = if s.source_id() == summary.source_id() { + debug!("Preventing\n{:?}\nfrom replacing\n{:?}", summary, s); + None + } else { + Some(s) + }; + let matched_spec = spec.clone(); + + // Make sure no duplicates + if let Some(&(ref spec, _)) = potential_matches.next() { + bail!("overlapping replacement specifications found:\n\n \ + * {}\n * {}\n\nboth specifications match: {}", + matched_spec, spec, summary.package_id()); + } + + for dep in summary.dependencies() { + debug!("\t{} => {}", dep.name(), dep.version_req()); + } + + candidate.replace = replace; + } + + // When we attempt versions for a package, we'll want to start at + // the maximum version and work our way down. + ret.sort_unstable_by(|a, b| { + b.summary.version().cmp(a.summary.version()) + }); + + let out = Rc::new(ret); + + self.cache.insert(dep.clone(), out.clone()); + + Ok(out) + } +} + #[derive(Clone)] struct BacktrackFrame<'a> { cur: usize, @@ -660,7 +762,7 @@ impl RemainingCandidates { /// dependency graph, cx.resolve is returned. fn activate_deps_loop<'a>( mut cx: Context<'a>, - registry: &mut Registry, + registry: &mut RegistryQueryer, summaries: &[(Summary, Method)], config: Option<&Config>, ) -> CargoResult> { @@ -780,7 +882,7 @@ fn activate_deps_loop<'a>( ).ok_or_else(|| { activation_error( &cx, - registry, + registry.registry, &parent, &dep, &conflicting_activations, @@ -1219,7 +1321,7 @@ impl<'a> Context<'a> { } fn build_deps(&mut self, - registry: &mut Registry, + registry: &mut RegistryQueryer, parent: Option<&Summary>, candidate: &Summary, method: &Method) -> ActivateResult> { @@ -1231,7 +1333,7 @@ impl<'a> Context<'a> { // Next, transform all dependencies into a list of possible candidates // which can satisfy that dependency. let mut deps = deps.into_iter().map(|(dep, features)| { - let candidates = self.query(registry, &dep)?; + let candidates = registry.query(&dep)?; Ok((dep, candidates, Rc::new(features))) }).collect::>>()?; @@ -1244,95 +1346,6 @@ impl<'a> Context<'a> { Ok(deps) } - /// Queries the `registry` to return a list of candidates for `dep`. - /// - /// This method is the location where overrides are taken into account. If - /// any candidates are returned which match an override then the override is - /// applied by performing a second query for what the override should - /// return. - fn query(&self, - registry: &mut Registry, - dep: &Dependency) -> CargoResult>> { - use ::std::cell::RefCell; - thread_local!(static CACHE: RefCell>>> = RefCell::new(BTreeMap::new())); - if let Some(out) = CACHE.with(|m| m.borrow().get(dep).cloned()) { - return Ok(out); - } - - let mut ret = Vec::new(); - registry.query(dep, &mut |s| { - ret.push(Candidate { summary: s, replace: None }); - })?; - for candidate in ret.iter_mut() { - let summary = &candidate.summary; - - let mut potential_matches = self.replacements.iter() - .filter(|&&(ref spec, _)| spec.matches(summary.package_id())); - - let &(ref spec, ref dep) = match potential_matches.next() { - None => continue, - Some(replacement) => replacement, - }; - debug!("found an override for {} {}", dep.name(), dep.version_req()); - - let mut summaries = registry.query_vec(dep)?.into_iter(); - let s = summaries.next().ok_or_else(|| { - format_err!("no matching package for override `{}` found\n\ - location searched: {}\n\ - version required: {}", - spec, dep.source_id(), dep.version_req()) - })?; - let summaries = summaries.collect::>(); - if !summaries.is_empty() { - let bullets = summaries.iter().map(|s| { - format!(" * {}", s.package_id()) - }).collect::>(); - bail!("the replacement specification `{}` matched \ - multiple packages:\n * {}\n{}", spec, s.package_id(), - bullets.join("\n")); - } - - // The dependency should be hard-coded to have the same name and an - // exact version requirement, so both of these assertions should - // never fail. - assert_eq!(s.version(), summary.version()); - assert_eq!(s.name(), summary.name()); - - let replace = if s.source_id() == summary.source_id() { - debug!("Preventing\n{:?}\nfrom replacing\n{:?}", summary, s); - None - } else { - Some(s) - }; - let matched_spec = spec.clone(); - - // Make sure no duplicates - if let Some(&(ref spec, _)) = potential_matches.next() { - bail!("overlapping replacement specifications found:\n\n \ - * {}\n * {}\n\nboth specifications match: {}", - matched_spec, spec, summary.package_id()); - } - - for dep in summary.dependencies() { - debug!("\t{} => {}", dep.name(), dep.version_req()); - } - - candidate.replace = replace; - } - - // When we attempt versions for a package, we'll want to start at - // the maximum version and work our way down. - ret.sort_unstable_by(|a, b| { - b.summary.version().cmp(a.summary.version()) - }); - - let out = Rc::new(ret); - - CACHE.with(|m| m.borrow_mut().insert(dep.clone(), out.clone())); - - Ok(out) - } - fn prev_active(&self, dep: &Dependency) -> &[Summary] { self.activations.get(dep.name()) .and_then(|v| v.get(dep.source_id())) -- 2.30.2