Make a `RegistryQueryer` to own the cache
authorEh2406 <YeomanYaacov@gmail.com>
Sat, 3 Mar 2018 15:56:57 +0000 (10:56 -0500)
committerEh2406 <YeomanYaacov@gmail.com>
Sat, 3 Mar 2018 16:07:46 +0000 (11:07 -0500)
src/cargo/core/resolver/mod.rs

index 44e9124d50c8bbf59bc3a9a3a70abbf63bc6a585..c169121a3cdc27dbf7a9fe8f1a641eb02e8a1af4 100644 (file)
@@ -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<Dependency, Rc<Vec<Candidate>>>,
+}
+
+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<Rc<Vec<Candidate>>> {
+        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::<Vec<_>>();
+            if !summaries.is_empty() {
+                let bullets = summaries.iter().map(|s| {
+                    format!("  * {}", s.package_id())
+                }).collect::<Vec<_>>();
+                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<Context<'a>> {
@@ -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<Vec<DepInfo>> {
@@ -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::<CargoResult<Vec<DepInfo>>>()?;
 
@@ -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<Rc<Vec<Candidate>>> {
-        use ::std::cell::RefCell;
-        thread_local!(static CACHE: RefCell<BTreeMap<Dependency, Rc<Vec<Candidate>>>> = 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::<Vec<_>>();
-            if !summaries.is_empty() {
-                let bullets = summaries.iter().map(|s| {
-                    format!("  * {}", s.package_id())
-                }).collect::<Vec<_>>();
-                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()))