mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
perf(resolver): hash once for the get + insert case (#606)
This commit is contained in:
parent
1d7f171309
commit
f094d5881e
3 changed files with 28 additions and 34 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
|
@ -736,6 +736,12 @@ dependencies = [
|
||||||
"libm",
|
"libm",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "identity-hash"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dfdd7caa900436d8f13b2346fe10257e0c05c1f1f9e351f4f5d57c03bd5f45da"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
|
@ -1500,6 +1506,7 @@ dependencies = [
|
||||||
"criterion",
|
"criterion",
|
||||||
"dashmap",
|
"dashmap",
|
||||||
"dunce",
|
"dunce",
|
||||||
|
"identity-hash",
|
||||||
"jemallocator",
|
"jemallocator",
|
||||||
"mimalloc",
|
"mimalloc",
|
||||||
"nodejs-resolver",
|
"nodejs-resolver",
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,12 @@ license.workspace = true
|
||||||
repository.workspace = true
|
repository.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dashmap = { workspace = true }
|
dashmap = { workspace = true }
|
||||||
serde = { workspace = true, features = ["derive"] }
|
serde = { workspace = true, features = ["derive"] }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
rustc-hash = { workspace = true }
|
rustc-hash = { workspace = true }
|
||||||
dunce = "1.0.4"
|
dunce = "1.0.4"
|
||||||
|
identity-hash = "0.1.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
static_assertions = { workspace = true }
|
static_assertions = { workspace = true }
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,26 @@
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Borrow,
|
|
||||||
convert::AsRef,
|
convert::AsRef,
|
||||||
hash::{BuildHasherDefault, Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::{Arc, OnceLock},
|
sync::{Arc, OnceLock},
|
||||||
};
|
};
|
||||||
|
|
||||||
use dashmap::DashSet;
|
use dashmap::DashMap;
|
||||||
|
use identity_hash::BuildIdentityHasher;
|
||||||
use rustc_hash::FxHasher;
|
use rustc_hash::FxHasher;
|
||||||
|
|
||||||
use crate::{package_json::PackageJson, FileMetadata, FileSystem, ResolveError};
|
use crate::{package_json::PackageJson, FileMetadata, FileSystem, ResolveError};
|
||||||
|
|
||||||
pub struct Cache<Fs> {
|
pub struct Cache<Fs> {
|
||||||
pub(crate) fs: Fs,
|
pub(crate) fs: Fs,
|
||||||
cache: DashSet<CacheValue, BuildHasherDefault<FxHasher>>,
|
// Using IdentityHasher to avoid double hashing in the `get` + `insert` case.
|
||||||
|
cache: DashMap<u64, CacheValue, BuildIdentityHasher<u64>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Fs: FileSystem> Default for Cache<Fs> {
|
impl<Fs: FileSystem> Default for Cache<Fs> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self { fs: Fs::default(), cache: DashSet::default() }
|
Self { fs: Fs::default(), cache: DashMap::default() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,18 +41,23 @@ impl<Fs: FileSystem> Cache<Fs> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value(&self, path: &Path) -> CacheValue {
|
pub fn value(&self, path: &Path) -> CacheValue {
|
||||||
if let Some(cache_entry) = self.cache.get(path) {
|
let hash = {
|
||||||
return cache_entry.key().clone();
|
let mut hasher = FxHasher::default();
|
||||||
|
path.hash(&mut hasher);
|
||||||
|
hasher.finish()
|
||||||
|
};
|
||||||
|
if let Some(cache_entry) = self.cache.get(&hash) {
|
||||||
|
return cache_entry.value().clone();
|
||||||
}
|
}
|
||||||
let parent = path.parent().map(|p| self.value(p));
|
let parent = path.parent().map(|p| self.value(p));
|
||||||
let data =
|
let data =
|
||||||
CacheValue(Arc::new(CacheValueImpl::new(path.to_path_buf().into_boxed_path(), parent)));
|
CacheValue(Arc::new(CacheValueImpl::new(path.to_path_buf().into_boxed_path(), parent)));
|
||||||
self.cache.insert(data.clone());
|
self.cache.insert(hash, data.clone());
|
||||||
data
|
data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CacheValue(Arc<CacheValueImpl>);
|
pub struct CacheValue(Arc<CacheValueImpl>);
|
||||||
|
|
||||||
impl Deref for CacheValue {
|
impl Deref for CacheValue {
|
||||||
|
|
@ -68,12 +74,6 @@ impl AsRef<CacheValueImpl> for CacheValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Borrow<Path> for CacheValue {
|
|
||||||
fn borrow(&self) -> &Path {
|
|
||||||
&self.path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CacheValueImpl {
|
pub struct CacheValueImpl {
|
||||||
path: Box<Path>,
|
path: Box<Path>,
|
||||||
|
|
@ -83,20 +83,6 @@ pub struct CacheValueImpl {
|
||||||
package_json: OnceLock<Option<Result<Arc<PackageJson>, ResolveError>>>,
|
package_json: OnceLock<Option<Result<Arc<PackageJson>, ResolveError>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for CacheValueImpl {
|
|
||||||
fn hash<H: Hasher>(&self, h: &mut H) {
|
|
||||||
self.path.hash(h);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for CacheValueImpl {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.path == other.path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for CacheValueImpl {}
|
|
||||||
|
|
||||||
impl CacheValueImpl {
|
impl CacheValueImpl {
|
||||||
fn new(path: Box<Path>, parent: Option<CacheValue>) -> Self {
|
fn new(path: Box<Path>, parent: Option<CacheValue>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue