Commit a4f5973
committed
Cache package version selection:
- ### Problem
Selecting a version for a given package is a extremelly hot path.
In a very large gemfile and a deep dependency tree (like the one
we have in our monolith at Shopify), this codepath is hit around 3.2
million times in total during the resolution phase.
### Context
When the resolution starts, Bundler fetch and turn every possible
versions of a gem that was ever released on Rubygems.org into a
possible candidate. We end up with a massive matrix of possibilites
that PubGrub has to go through. In the case of a large Gemfile
like we have, we end up with ~55,000 candidates.
Many of this candidate have conflicting dependencies requirements
and as pubgrub progress, it will continously ask over and over the
same things: "Return the possible candidates given this version
constraint" (`range.select_versions(@sorted_versions[package])`).
Since this path is called so frequently (sometimes more than 8000
times for a single candidate and the same constraint), the returned
value can be cached for faster access.
### Solution
Cache the selected versions for a given constraint in a hash.
The key being an array where the first element is the package we want
to resolve and the second element is the constraint. The associated
value is all possible candidates matching.
If the resolver end up not finding a candidate (in example you run
`bundle install --prefer-local`) then Bundler will allow finding
candidates on the remote. In this case we need to invalidate the
cache as otherwise the candidates from the remotes will not
be considered.
### Benchmark
This change has a huge impact on resolution time. Those measures
were taken on Shopify monolith by removing the lockfile and measuring
only resolution time (no network or external factors affect these
results.)
┌─────┬──────────┬───────────┬─────────┐
│ Run │ Original │ Optimized │ Speedup │
├─────┼──────────┼───────────┼─────────┤
│ 1 │ 19.20s │ 10.32s │ 46.3% │
├─────┼──────────┼───────────┼─────────┤
│ 2 │ 19.17s │ 10.46s │ 45.4% │
├─────┼──────────┼───────────┼─────────┤
│ 3 │ 18.95s │ 10.29s │ 45.7% │
├─────┼──────────┼───────────┼─────────┤
│ 4 │ 19.17s │ 10.37s │ 45.9% │
├─────┼──────────┼───────────┼─────────┤
│ 5 │ 19.26s │ 10.30s │ 46.5% │
├─────┼──────────┼───────────┼─────────┤
│ Avg │ 19.15s │ 10.35s │ 46.0% │
└─────┴──────────┴───────────┴─────────┘1 parent edf0012 commit a4f5973
1 file changed
Lines changed: 6 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
| |||
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
20 | | - | |
21 | | - | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
22 | 24 | | |
23 | | - | |
| 25 | + | |
| 26 | + | |
24 | 27 | | |
25 | 28 | | |
26 | 29 | | |
| |||
0 commit comments