gnodet opened a new pull request, #1941:
URL: https://github.com/apache/maven-resolver/pull/1941

   ## Summary
   
   `ScopeDependencySelector` and `OptionalDependencySelector` (in `impl.scope` 
package) always create new instances in `deriveChildSelector()`, incrementing 
`depth` at every level. Since `depth` is part of `equals()`/`hashCode()`, every 
tree depth produces a unique selector, which makes the `DataPool`/`GraphKey` 
cache in the DF dependency collector miss on every lookup across depths.
   
   This causes **exponential node growth** in the DF collector for large 
dependency trees. In a benchmark with a large multi-module project:
   
   | Configuration | Node count |
   |---|---|
   | Resolver 1.9.27 (Maven 3.9.16), DF collector | 1,054,704 |
   | Resolver 2.0.x (Maven 3.10.x), BF collector | 1,915,842 |
   | Resolver 2.0.x (Maven 3.10.x), DF collector | 9,893,981 |
   
   The DF collector's 9.4x node increase is caused by cache misses cascading 
exponentially — each miss triggers full recursion, discovering more nodes that 
also miss the cache.
   
   ## Root cause
   
   The old selectors (resolver 1.x, in `util.graph.selector` package) returned 
`this` from `deriveChildSelector()` once their behavior stabilized:
   
   - `ScopeDependencySelector`: returned `this` once `transitive=true` (after 
depth 1)
   - `OptionalDependencySelector`: returned `this` once `depth >= 2`
   
   The `AndDependencySelector` already optimizes for this pattern (line 119): 
when all child selectors return `this` (reference equality), the 
`AndDependencySelector` also returns `this`. This meant the entire composite 
selector was the **same instance** at all depths 2+, enabling cache hits in the 
`GraphKey`.
   
   The new `impl.scope` selectors never return `this` — they always create new 
instances with `depth + 1`, breaking this optimization chain.
   
   ## Fix
   
   Both selectors now return `this` from `deriveChildSelector()` once `depth >= 
applyFrom` (the point after which their `selectDependency()` behavior no longer 
changes with depth). For `ScopeDependencySelector`, the only exception is 
`depth == applyTo` where behavior transitions from "filter by scope" to "accept 
all".
   
   For the default Maven 3.10.x configuration 
(`ScopeDependencySelector.legacy(null, ["test", "provided"])`), this means the 
selector stabilizes at depth 2, matching the old resolver 1.x behavior.
   
   _Claude Code on behalf of Guillaume Nodet_


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to