Skip to content

Commit 83f22c4

Browse files
Boshenclaude
andcommitted
perf: use arena with RwLock for package.json storage
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent e1ef00d commit 83f22c4

File tree

4 files changed

+77
-8
lines changed

4 files changed

+77
-8
lines changed

Cargo.lock

Lines changed: 39 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ indexmap = { version = "2", features = ["serde"] }
8282
json-strip-comments = "3"
8383
once_cell = "1" # Use `std::sync::OnceLock::get_or_try_init` when it is stable.
8484
papaya = "0.2"
85+
parking_lot = "0.12"
8586
rustc-hash = { version = "2" }
8687
serde = { version = "1", features = ["derive"] } # derive for Deserialize from package.json
8788
serde_json = { version = "1", features = ["preserve_order"] } # preserve_order: package_json.exports requires order such as `["require", "import", "default"]`
@@ -152,8 +153,8 @@ rustdoc-args = ["--cfg", "docsrs"]
152153
opt-level = 3
153154
lto = "fat"
154155
codegen-units = 1
155-
strip = "symbols" # set to `false` for debug information
156-
debug = false # set to `true` for debug information
156+
strip = false # "symbols" # set to `false` for debug information
157+
debug = true # set to `true` for debug information
157158
panic = "abort" # Let it crash and force ourselves to write safe Rust.
158159

159160
[profile.release.package.regex-automata]

src/cache/cache_impl.rs

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use std::{
77
sync::Arc,
88
};
99

10+
use parking_lot::RwLock;
11+
1012
use cfg_if::cfg_if;
1113
#[cfg(feature = "yarn_pnp")]
1214
use once_cell::sync::OnceCell;
@@ -22,11 +24,11 @@ use crate::{
2224
};
2325

2426
/// Cache implementation used for caching filesystem access.
25-
#[derive(Default)]
2627
pub struct Cache<Fs> {
2728
pub(crate) fs: Fs,
2829
pub(crate) paths: HashSet<CachedPath, BuildHasherDefault<IdentityHasher>>,
2930
pub(crate) tsconfigs: HashMap<PathBuf, Arc<TsConfig>, BuildHasherDefault<FxHasher>>,
31+
pub(crate) package_json_arena: RwLock<Vec<Arc<PackageJson>>>,
3032
#[cfg(feature = "yarn_pnp")]
3133
pub(crate) yarn_pnp_manifest: OnceCell<pnp::Manifest>,
3234
}
@@ -35,6 +37,7 @@ impl<Fs: FileSystem> Cache<Fs> {
3537
pub fn clear(&self) {
3638
self.paths.pin().clear();
3739
self.tsconfigs.pin().clear();
40+
self.package_json_arena.write().clear();
3841
}
3942

4043
#[allow(clippy::cast_possible_truncation)]
@@ -105,7 +108,7 @@ impl<Fs: FileSystem> Cache<Fs> {
105108
ctx: &mut Ctx,
106109
) -> Result<Option<Arc<PackageJson>>, ResolveError> {
107110
// Change to `std::sync::OnceLock::get_or_try_init` when it is stable.
108-
let result = path
111+
let index_result = path
109112
.package_json
110113
.get_or_try_init(|| {
111114
let package_json_path = path.path.join("package.json");
@@ -119,10 +122,35 @@ impl<Fs: FileSystem> Cache<Fs> {
119122
package_json_path.clone()
120123
};
121124
PackageJson::parse(&self.fs, package_json_path, real_path, package_json_bytes)
122-
.map(|package_json| Some(Arc::new(package_json)))
125+
.map(|package_json| {
126+
let arc = Arc::new(package_json);
127+
// Acquire write lock to push to arena
128+
let mut arena = self.package_json_arena.write();
129+
let index = arena.len();
130+
arena.push(arc);
131+
Some(index)
132+
})
123133
.map_err(ResolveError::Json)
124-
})
125-
.cloned();
134+
});
135+
136+
// Lookup the Arc from the arena using the stored index
137+
let result = index_result.and_then(|index_opt| {
138+
match index_opt {
139+
Some(index) => {
140+
// Get the Arc from the arena
141+
let arena = self.package_json_arena.read();
142+
arena.get(*index)
143+
.map(|arc| Ok(Some(Arc::clone(arc))))
144+
.unwrap_or_else(|| {
145+
// Index out of bounds (e.g., after cache clear)
146+
// Return None to indicate package.json not found
147+
Ok(None)
148+
})
149+
}
150+
None => Ok(None)
151+
}
152+
});
153+
126154
// https://github.com/webpack/enhanced-resolve/blob/58464fc7cb56673c9aa849e68e6300239601e615/lib/DescriptionFileUtils.js#L68-L82
127155
match &result {
128156
Ok(Some(package_json)) => {
@@ -216,6 +244,7 @@ impl<Fs: FileSystem> Cache<Fs> {
216244
.hasher(BuildHasherDefault::default())
217245
.resize_mode(papaya::ResizeMode::Blocking)
218246
.build(),
247+
package_json_arena: RwLock::new(Vec::new()),
219248
#[cfg(feature = "yarn_pnp")]
220249
yarn_pnp_manifest: OnceCell::new(),
221250
}

src/cache/cached_path.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ pub struct CachedPathImpl {
2929
pub meta: OnceLock<Option<FileMetadata>>,
3030
pub canonicalized: OnceLock<Result<Weak<CachedPathImpl>, ResolveError>>,
3131
pub node_modules: OnceLock<Option<Weak<CachedPathImpl>>>,
32-
pub package_json: OnceLock<Option<Arc<PackageJson>>>,
32+
pub package_json: OnceLock<Option<usize>>,
3333
pub tsconfig: OnceLock<Option<Arc<TsConfig>>>,
3434
}
3535

0 commit comments

Comments
 (0)