/
githubmirror
/
deno
Обзор
Документация
Войти
/
githubmirror
/
deno
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
libs/node_resolver/cache.rs
220 строк
6 KB
Bartek Iwańczuk
perf: use FxHash for hot internal hash maps (#36100)
20 июл 2026, 12:09
Не верифицирован
20 июл 2026, 12:09
f9ea4e8
Код
Авторство
О чём код?
// Copyright 2018-2026 the Deno authors. MIT license. use std::borrow::Cow; use std::cell::RefCell; use std::path::Path; use std::path::PathBuf; use rustc_hash::FxHashMap; use sys_traits::BaseFsCanonicalize; use sys_traits::BaseFsOpen; use sys_traits::BaseFsRead; use sys_traits::BaseFsReadDir; use sys_traits::FileType; use sys_traits::FsCanonicalize; use sys_traits::FsMetadata; use sys_traits::FsMetadataValue; use sys_traits::FsOpen; use sys_traits::FsRead; use sys_traits::FsReadDir; pub trait NodeResolutionCache: std::fmt::Debug + deno_maybe_sync::MaybeSend + deno_maybe_sync::MaybeSync { fn get_canonicalized( &self, path: &Path, ) -> Option<Result<PathBuf, std::io::Error>>; fn set_canonicalized(&self, from: PathBuf, to: &std::io::Result<PathBuf>); fn get_file_type(&self, path: &Path) -> Option<Option<FileType>>; fn set_file_type(&self, path: PathBuf, value: Option<FileType>); } thread_local! { static CANONICALIZED_CACHE: RefCell<FxHashMap<PathBuf, Option<PathBuf>>> = RefCell::new(FxHashMap::default()); static FILE_TYPE_CACHE: RefCell<FxHashMap<PathBuf, Option<FileType>>> = RefCell::new(FxHashMap::default()); } // We use thread local caches here because it's just more convenient // and easily allows workers to have separate caches. #[derive(Debug)] pub struct NodeResolutionThreadLocalCache; impl NodeResolutionThreadLocalCache { pub fn clear() { CANONICALIZED_CACHE.with_borrow_mut(|cache| cache.clear()); FILE_TYPE_CACHE.with_borrow_mut(|cache| cache.clear()); } } impl NodeResolutionCache for NodeResolutionThreadLocalCache { fn get_canonicalized( &self, path: &Path, ) -> Option<Result<PathBuf, std::io::Error>> { CANONICALIZED_CACHE.with_borrow(|cache| { let item = cache.get(path)?; Some(match item { Some(value) => Ok(value.clone()), None => Err(std::io::Error::new( std::io::ErrorKind::NotFound, "Not found.", )), }) }) } fn set_canonicalized(&self, from: PathBuf, to: &std::io::Result<PathBuf>) { CANONICALIZED_CACHE.with_borrow_mut(|cache| match to { Ok(to) => { cache.insert(from, Some(to.clone())); } Err(err) => { if err.kind() == std::io::ErrorKind::NotFound { cache.insert(from, None); } } }); } fn get_file_type(&self, path: &Path) -> Option<Option<FileType>> { FILE_TYPE_CACHE.with_borrow(|cache| cache.get(path).cloned()) } fn set_file_type(&self, path: PathBuf, value: Option<FileType>) { FILE_TYPE_CACHE.with_borrow_mut(|cache| { cache.insert(path, value); }) } } #[allow(clippy::disallowed_types, reason = "definition")] pub type NodeResolutionCacheRc = deno_maybe_sync::MaybeArc<dyn NodeResolutionCache>; #[derive(Debug, Default)] pub struct NodeResolutionSys<TSys> { sys: TSys, cache: Option<NodeResolutionCacheRc>, } impl<TSys: Clone> Clone for NodeResolutionSys<TSys> { fn clone(&self) -> Self { Self { sys: self.sys.clone(), cache: self.cache.clone(), } } } impl<TSys: FsMetadata> NodeResolutionSys<TSys> { pub fn new(sys: TSys, store: Option<NodeResolutionCacheRc>) -> Self { Self { sys, cache: store } } pub fn has_cache(&self) -> bool { self.cache.is_some() } pub fn is_file(&self, path: Cow<'_, Path>) -> bool { match self.get_file_type(path) { Ok(file_type) => file_type.is_file(), Err(_) => false, } } pub fn is_dir(&self, path: Cow<'_, Path>) -> bool { match self.get_file_type(path) { Ok(file_type) => file_type.is_dir(), Err(_) => false, } } pub fn exists_(&self, path: Cow<'_, Path>) -> bool { self.get_file_type(path).is_ok() } pub fn get_file_type( &self, path: Cow<'_, Path>, ) -> std::io::Result<FileType> { { if let Some(maybe_value) = self.cache.as_ref().and_then(|c| c.get_file_type(&path)) { return match maybe_value { Some(value) => Ok(value), None => Err(std::io::Error::new( std::io::ErrorKind::NotFound, "Not found.", )), }; } } match self.sys.fs_metadata(&path) { Ok(metadata) => { if let Some(cache) = &self.cache { cache.set_file_type(path.into_owned(), Some(metadata.file_type())); } Ok(metadata.file_type()) } Err(err) => { if let Some(cache) = &self.cache { cache.set_file_type(path.into_owned(), None); } Err(err) } } } } impl<TSys: FsCanonicalize> BaseFsCanonicalize for NodeResolutionSys<TSys> { fn base_fs_canonicalize(&self, from: &Path) -> std::io::Result<PathBuf> { if let Some(cache) = &self.cache && let Some(result) = cache.get_canonicalized(from) { return result; } let result = self.sys.base_fs_canonicalize(from); if let Some(cache) = &self.cache { cache.set_canonicalized(from.to_path_buf(), &result); } result } } impl<TSys: FsReadDir> BaseFsReadDir for NodeResolutionSys<TSys> { type ReadDirEntry = TSys::ReadDirEntry; #[inline(always)] fn base_fs_read_dir( &self, path: &Path, ) -> std::io::Result< Box<dyn Iterator<Item = std::io::Result<Self::ReadDirEntry>>>, > { self.sys.base_fs_read_dir(path) } } impl<TSys: FsRead> BaseFsRead for NodeResolutionSys<TSys> { #[inline(always)] fn base_fs_read( &self, path: &Path, ) -> std::io::Result<std::borrow::Cow<'static, [u8]>> { self.sys.base_fs_read(path) } } impl<TSys: FsOpen> BaseFsOpen for NodeResolutionSys<TSys> { type File = TSys::File; fn base_fs_open( &self, path: &Path, flags: &sys_traits::OpenOptions, ) -> std::io::Result<Self::File> { self.sys.base_fs_open(path, flags) } }