refactor(cache): replace papaya with dashmap#1214
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1214 +/- ##
==========================================
- Coverage 93.77% 93.70% -0.07%
==========================================
Files 22 21 -1
Lines 4227 4197 -30
==========================================
- Hits 3964 3933 -31
- Misses 263 264 +1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
9796f3d to
3162d63
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fdaf9a475e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
papaya's lock-free implementation compiles to more code than dashmap's sharded RwLock, so swapping it shrinks the published darwin-arm64 .node by ~16 KB (1,685,744 -> 1,669,536) even though dashmap pulls more dependency crates. The paths set keeps CachedPath as the key and IdentityHasher, which feeds the hash memoized on CachedPath straight through. Since IdentityHasher only accepts a single write_u64, the set can't be probed by a borrowed &Path via dashmap's Borrow-based get, so Cache::value looks it up through the raw-api (precomputed hash + OsStr equality on the shard) -- the direct analog of the Equivalent lookup the papaya set used, and still zero-alloc. Cache::value keeps the parent-chain recursion unlocked, as papaya's non-locking .pin() guard allowed, then dedups the final insert with entry() so concurrent first-touches of a path converge to one shared Arc, preserving the identity the canonicalized / node_modules weak-pointer caches rely on. Removes the now-dead borrowed_path module. Trade-off: cache reads move from lock-free to sharded-lock. All tests pass but concurrent throughput is not benchmarked.
3162d63 to
150f951
Compare
Merging this PR will improve performance by 4.12%
Performance Changes
Tip Curious why this is faster? Comment Comparing Footnotes
|
## 🤖 New release * `oxc_resolver`: 11.21.0 -> 11.21.1 * `oxc_resolver_napi`: 11.21.0 -> 11.21.1 <details><summary><i><b>Changelog</b></i></summary><p> ## `oxc_resolver` <blockquote> ## [11.21.1](v11.21.0...v11.21.1) - 2026-06-17 ### <!-- 1 -->🐛 Bug Fixes - *(tsconfig)* walk up for non-TS and `allowJs`-off `.js` importers ([#1216](#1216)) (by @shulaoda) - *(tsconfig)* honor explicit non-TS extensions in `include` ([#1213](#1213)) (by @shulaoda) ### <!-- 2 -->🚜 Refactor - *(cache)* replace papaya with dashmap ([#1214](#1214)) (by @Boshen) ### <!-- 6 -->🧪 Testing - verify node_modules canonicalization across layouts ([#1200](#1200)) (by @Boshen) ### Contributors * @shulaoda * @Boshen </blockquote> </p></details> --- This PR was generated with [release-plz](https://github.com/release-plz/release-plz/). Co-authored-by: oxc-guard[bot] <276638029+oxc-guard[bot]@users.noreply.github.com>
Summary
Replaces
papayawithdashmapfor the resolver's path / tsconfig cache.papaya's lock-free implementation compiles to more code thandashmap's shardedRwLock, so the swap shrinks the published binary and turns out a touch faster — even thoughdashmappulls more dependency crates.Binary size
Measured on the darwin-arm64
.node(built with mimalloc, like CI):papaya(baseline)dashmapcdylib (without mimalloc): 1,601,872 → 1,585,680 (−16,192).
Performance
CodSpeed reports a net +4.12%, with 4 benchmarks faster, 17 untouched, and none regressed — so the lock-free → sharded-lock change is a win in practice, not a trade-off (the restored memoized-hash
IdentityHasheravoids re-hashing, and dashmap's reads skip papaya's epoch-reclamation overhead):pm/npm-flatpm/bun-isolatedpackage_json_deserialization/mediumresolver_real[resolve from symlinks](The CodSpeed suite is single-threaded, so it measures resolution speed rather than worst-case parallel cache contention.)
Port details
pathsset keepsCachedPathas the key withIdentityHasher, which feeds the hash memoized onCachedPathstraight through — no path duplication, no re-hashing. BecauseIdentityHasheronly accepts a singlewrite_u64, the set can't be probed by a borrowed&Paththrough dashmap'sBorrow-basedget;Cache::valueinstead looks it up via the raw-api (precomputed hash +OsStrequality on the shard) — the direct analog of theEquivalentlookup thepapayaset used, still zero-alloc andunsafe-free.Cache::valuekeeps the parent-chain recursion unlocked (aspapaya's non-locking.pin()allowed), then dedups the final insert viaentry()so concurrent first-touches of a path converge to one sharedArc— preserving the identity thecanonicalized/node_modulesweak-pointer caches depend on.borrowed_pathmodule (Equivalentborrowed-lookup helper).Validation
cargo test+cargo test --all-features(unit + integration + PnP),cargo clippy --all-features --all-targets -D warnings,cargo check --target s390x-unknown-linux-gnu,cargo shear, andnode --run build+node --run teston the rebuilt.node— all green. CI green across all platforms incl. big-endian, wasm, and CodSpeed.