mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 07:14:47 -05:00
perf(npm): make dependency resolution faster (#16694)
This commit is contained in:
parent
409e6c8402
commit
5867a12920
1 changed files with 28 additions and 6 deletions
|
@ -139,6 +139,11 @@ struct Node {
|
||||||
pub parents: BTreeMap<String, BTreeSet<NodeParent>>,
|
pub parents: BTreeMap<String, BTreeSet<NodeParent>>,
|
||||||
pub children: BTreeMap<String, NpmPackageId>,
|
pub children: BTreeMap<String, NpmPackageId>,
|
||||||
pub deps: Arc<Vec<NpmDependencyEntry>>,
|
pub deps: Arc<Vec<NpmDependencyEntry>>,
|
||||||
|
/// Whether the node has demonstrated to have no peer dependencies in its
|
||||||
|
/// descendants. If this is true then we can skip analyzing this node
|
||||||
|
/// again when we encounter it another time in the dependency tree, which
|
||||||
|
/// is much faster.
|
||||||
|
pub no_peers: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node {
|
impl Node {
|
||||||
|
@ -225,6 +230,7 @@ impl Graph {
|
||||||
parents: Default::default(),
|
parents: Default::default(),
|
||||||
children: Default::default(),
|
children: Default::default(),
|
||||||
deps: Default::default(),
|
deps: Default::default(),
|
||||||
|
no_peers: false,
|
||||||
}));
|
}));
|
||||||
self
|
self
|
||||||
.packages_by_name
|
.packages_by_name
|
||||||
|
@ -492,7 +498,7 @@ impl<'a, TNpmRegistryApi: NpmRegistryApi>
|
||||||
package_info: &NpmPackageInfo,
|
package_info: &NpmPackageInfo,
|
||||||
parent_id: &NpmPackageId,
|
parent_id: &NpmPackageId,
|
||||||
visited_versions: &Arc<VisitedVersionsPath>,
|
visited_versions: &Arc<VisitedVersionsPath>,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<Arc<Mutex<Node>>, AnyError> {
|
||||||
let node = self.resolve_node_from_info(
|
let node = self.resolve_node_from_info(
|
||||||
&entry.name,
|
&entry.name,
|
||||||
match entry.kind {
|
match entry.kind {
|
||||||
|
@ -515,7 +521,7 @@ impl<'a, TNpmRegistryApi: NpmRegistryApi>
|
||||||
&NodeParent::Node(parent_id.clone()),
|
&NodeParent::Node(parent_id.clone()),
|
||||||
);
|
);
|
||||||
self.try_add_pending_unresolved_node(Some(visited_versions), &node);
|
self.try_add_pending_unresolved_node(Some(visited_versions), &node);
|
||||||
Ok(())
|
Ok(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_add_pending_unresolved_node(
|
fn try_add_pending_unresolved_node(
|
||||||
|
@ -523,7 +529,13 @@ impl<'a, TNpmRegistryApi: NpmRegistryApi>
|
||||||
maybe_previous_visited_versions: Option<&Arc<VisitedVersionsPath>>,
|
maybe_previous_visited_versions: Option<&Arc<VisitedVersionsPath>>,
|
||||||
node: &Arc<Mutex<Node>>,
|
node: &Arc<Mutex<Node>>,
|
||||||
) {
|
) {
|
||||||
let node_id = node.lock().id.clone();
|
let node_id = {
|
||||||
|
let node = node.lock();
|
||||||
|
if node.no_peers {
|
||||||
|
return; // skip, no need to analyze this again
|
||||||
|
}
|
||||||
|
node.id.clone()
|
||||||
|
};
|
||||||
let visited_versions = match maybe_previous_visited_versions {
|
let visited_versions = match maybe_previous_visited_versions {
|
||||||
Some(previous_visited_versions) => {
|
Some(previous_visited_versions) => {
|
||||||
match previous_visited_versions.with_id(&node_id) {
|
match previous_visited_versions.with_id(&node_id) {
|
||||||
|
@ -576,6 +588,7 @@ impl<'a, TNpmRegistryApi: NpmRegistryApi>
|
||||||
// so these are resolved in that order
|
// so these are resolved in that order
|
||||||
deps.sort();
|
deps.sort();
|
||||||
node.deps = Arc::new(deps);
|
node.deps = Arc::new(deps);
|
||||||
|
node.no_peers = node.deps.is_empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(node)
|
Ok(node)
|
||||||
|
@ -589,8 +602,8 @@ impl<'a, TNpmRegistryApi: NpmRegistryApi>
|
||||||
{
|
{
|
||||||
let (mut parent_id, deps, existing_children) = {
|
let (mut parent_id, deps, existing_children) = {
|
||||||
let parent_node = parent_node.lock();
|
let parent_node = parent_node.lock();
|
||||||
if parent_node.forgotten {
|
if parent_node.forgotten || parent_node.no_peers {
|
||||||
// todo(dsherret): we should try to reproduce this scenario and write a test
|
// todo(dsherret): we should try to reproduce this forgotten scenario and write a test
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -622,20 +635,25 @@ impl<'a, TNpmRegistryApi: NpmRegistryApi>
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolve the dependencies
|
// resolve the dependencies
|
||||||
|
let mut found_peer = false;
|
||||||
for dep in deps.iter() {
|
for dep in deps.iter() {
|
||||||
let package_info = self.api.package_info(&dep.name).await?;
|
let package_info = self.api.package_info(&dep.name).await?;
|
||||||
|
|
||||||
match dep.kind {
|
match dep.kind {
|
||||||
NpmDependencyEntryKind::Dep => {
|
NpmDependencyEntryKind::Dep => {
|
||||||
self.analyze_dependency(
|
let node = self.analyze_dependency(
|
||||||
dep,
|
dep,
|
||||||
&package_info,
|
&package_info,
|
||||||
&parent_id,
|
&parent_id,
|
||||||
&visited_versions,
|
&visited_versions,
|
||||||
)?;
|
)?;
|
||||||
|
if !found_peer {
|
||||||
|
found_peer = !node.lock().no_peers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
NpmDependencyEntryKind::Peer
|
NpmDependencyEntryKind::Peer
|
||||||
| NpmDependencyEntryKind::OptionalPeer => {
|
| NpmDependencyEntryKind::OptionalPeer => {
|
||||||
|
found_peer = true;
|
||||||
let maybe_new_parent_id = self.resolve_peer_dep(
|
let maybe_new_parent_id = self.resolve_peer_dep(
|
||||||
&dep.bare_specifier,
|
&dep.bare_specifier,
|
||||||
&parent_id,
|
&parent_id,
|
||||||
|
@ -654,6 +672,10 @@ impl<'a, TNpmRegistryApi: NpmRegistryApi>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !found_peer {
|
||||||
|
self.graph.borrow_node(&parent_id).no_peers = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
Loading…
Reference in a new issue