summaryrefslogtreecommitdiff
path: root/cli/npm/resolution/mod.rs
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2022-11-11 11:33:57 -0500
committerGitHub <noreply@github.com>2022-11-11 11:33:57 -0500
commit8dc242f7891492886827a350b7736c11df7aa419 (patch)
treef9d9ceca4361c71ba08b0e304d2e4a1696ed9140 /cli/npm/resolution/mod.rs
parent7f0546a6b736430e6c39c55cfa77f39e70ffc9a2 (diff)
perf: more efficient `deno cache` and npm package info usage (#16592)
1. There was a lot of cloning going on with `NpmPackageInfo`. This is now stored in an `Arc<NpmPackageInfo>` and cloning only happens on the individual version. 2. The package cache is now cleared from memory after resolution. 3. This surfaced a bug in `deno cache` and I noticed it can be more efficient if we have multiple root specifiers if we provide all the specifiers as roots.
Diffstat (limited to 'cli/npm/resolution/mod.rs')
-rw-r--r--cli/npm/resolution/mod.rs50
1 files changed, 31 insertions, 19 deletions
diff --git a/cli/npm/resolution/mod.rs b/cli/npm/resolution/mod.rs
index 934cfb59b..381e350c9 100644
--- a/cli/npm/resolution/mod.rs
+++ b/cli/npm/resolution/mod.rs
@@ -422,42 +422,54 @@ impl NpmResolution {
// multiple packages are resolved in alphabetical order
package_reqs.sort_by(|a, b| a.name.cmp(&b.name));
- // go over the top level packages first, then down the
+ // go over the top level package names first, then down the
// tree one level at a time through all the branches
let mut unresolved_tasks = Vec::with_capacity(package_reqs.len());
- for package_req in package_reqs {
- if graph.has_package_req(&package_req) {
+ let mut resolving_package_names =
+ HashSet::with_capacity(package_reqs.len());
+ for package_req in &package_reqs {
+ if graph.has_package_req(package_req) {
// skip analyzing this package, as there's already a matching top level package
continue;
}
+ if !resolving_package_names.insert(package_req.name.clone()) {
+ continue; // already resolving
+ }
- // no existing best version, so resolve the current packages
- let api = self.api.clone();
- let maybe_info = if should_sync_download() {
+ // cache the package info up front in parallel
+ if should_sync_download() {
// for deterministic test output
- Some(api.package_info(&package_req.name).await)
+ self.api.package_info(&package_req.name).await?;
} else {
- None
+ let api = self.api.clone();
+ let package_name = package_req.name.clone();
+ unresolved_tasks.push(tokio::task::spawn(async move {
+ // This is ok to call because api will internally cache
+ // the package information in memory.
+ api.package_info(&package_name).await
+ }));
};
- unresolved_tasks.push(tokio::task::spawn(async move {
- let info = match maybe_info {
- Some(info) => info?,
- None => api.package_info(&package_req.name).await?,
- };
- Result::<_, AnyError>::Ok((package_req, info))
- }));
+ }
+
+ for result in futures::future::join_all(unresolved_tasks).await {
+ result??; // surface the first error
}
let mut resolver = GraphDependencyResolver::new(&mut graph, &self.api);
- for result in futures::future::join_all(unresolved_tasks).await {
- let (package_req, info) = result??;
- resolver.add_package_req(&package_req, info)?;
+ for package_req in package_reqs {
+ // avoid loading the info if this is already in the graph
+ if !resolver.has_package_req(&package_req) {
+ let info = self.api.package_info(&package_req.name).await?;
+ resolver.add_package_req(&package_req, &info)?;
+ }
}
resolver.resolve_pending().await?;
- graph.into_snapshot(&self.api).await
+ let result = graph.into_snapshot(&self.api).await;
+ self.api.clear_memory_cache();
+ result
}
pub fn resolve_package_from_id(