@@ -13,8 +13,8 @@ use std::{
1313} ;
1414
1515use cfg_if:: cfg_if;
16- use dashmap:: { DashMap , DashSet } ;
1716use once_cell:: sync:: OnceCell as OnceLock ;
17+ use papaya:: { Equivalent , HashMap , HashSet } ;
1818use rustc_hash:: FxHasher ;
1919
2020use crate :: {
@@ -38,50 +38,16 @@ thread_local! {
3838#[ derive( Default ) ]
3939pub struct FsCache < Fs > {
4040 pub ( crate ) fs : Fs ,
41- paths : DashSet < PathEntry < ' static > , BuildHasherDefault < IdentityHasher > > ,
42- tsconfigs : DashMap < PathBuf , Arc < TsConfig > , BuildHasherDefault < FxHasher > > ,
41+ paths : HashSet < FsCachedPath , BuildHasherDefault < IdentityHasher > > ,
42+ tsconfigs : HashMap < PathBuf , Arc < TsConfig > , BuildHasherDefault < FxHasher > > ,
4343}
4444
45- /// An entry in the path cache. Can also be borrowed for lookups without allocations.
46- enum PathEntry < ' a > {
47- Owned ( FsCachedPath ) ,
48- Borrowed { hash : u64 , path : & ' a Path } ,
49- }
50-
51- impl Hash for PathEntry < ' _ > {
52- fn hash < H : Hasher > ( & self , state : & mut H ) {
53- match self {
54- PathEntry :: Owned ( entry) => {
55- entry. hash . hash ( state) ;
56- }
57- PathEntry :: Borrowed { hash, .. } => {
58- hash. hash ( state) ;
59- }
60- }
61- }
62- }
63-
64- impl PartialEq for PathEntry < ' _ > {
65- fn eq ( & self , other : & Self ) -> bool {
66- let self_path = match self {
67- PathEntry :: Owned ( info) => & info. path ,
68- PathEntry :: Borrowed { path, .. } => * path,
69- } ;
70- let other_path = match other {
71- PathEntry :: Owned ( info) => & info. path ,
72- PathEntry :: Borrowed { path, .. } => * path,
73- } ;
74- self_path. as_os_str ( ) == other_path. as_os_str ( )
75- }
76- }
77- impl Eq for PathEntry < ' _ > { }
78-
7945impl < Fs : FileSystem > Cache for FsCache < Fs > {
8046 type Cp = FsCachedPath ;
8147
8248 fn clear ( & self ) {
83- self . paths . clear ( ) ;
84- self . tsconfigs . clear ( ) ;
49+ self . paths . pin ( ) . clear ( ) ;
50+ self . tsconfigs . pin ( ) . clear ( ) ;
8551 }
8652
8753 #[ allow( clippy:: cast_possible_truncation) ]
@@ -93,25 +59,17 @@ impl<Fs: FileSystem> Cache for FsCache<Fs> {
9359 path. as_os_str ( ) . hash ( & mut hasher) ;
9460 hasher. finish ( )
9561 } ;
96- let key = PathEntry :: Borrowed { hash, path } ;
97- // A DashMap is just an array of RwLock<HashSet>, sharded by hash to reduce lock contention.
98- // This uses the low level raw API to avoid cloning the value when using the `entry` method.
99- // First, find which shard the value is in, and check to see if we already have a value in the map.
100- let shard = self . paths . determine_shard ( hash as usize ) ;
101- {
102- // Scope the read lock.
103- let map = self . paths . shards ( ) [ shard] . read ( ) ;
104- if let Some ( ( PathEntry :: Owned ( entry) , _) ) = map. get ( hash, |v| v. 0 == key) {
105- return entry. clone ( ) ;
106- }
62+ let paths = self . paths . pin ( ) ;
63+ if let Some ( entry) = paths. get ( & BorrowedCachedPath { hash, path } ) {
64+ return entry. clone ( ) ;
10765 }
10866 let parent = path. parent ( ) . map ( |p| self . value ( p) ) ;
10967 let cached_path = FsCachedPath ( Arc :: new ( CachedPathImpl :: new (
11068 hash,
11169 path. to_path_buf ( ) . into_boxed_path ( ) ,
11270 parent,
11371 ) ) ) ;
114- self . paths . insert ( PathEntry :: Owned ( cached_path. clone ( ) ) ) ;
72+ paths. insert ( cached_path. clone ( ) ) ;
11573 cached_path
11674 }
11775
@@ -196,8 +154,9 @@ impl<Fs: FileSystem> Cache for FsCache<Fs> {
196154 path : & Path ,
197155 callback : F , // callback for modifying tsconfig with `extends`
198156 ) -> Result < Arc < TsConfig > , ResolveError > {
199- if let Some ( tsconfig) = self . tsconfigs . get ( path) {
200- return Ok ( Arc :: clone ( & tsconfig) ) ;
157+ let tsconfigs = self . tsconfigs . pin ( ) ;
158+ if let Some ( tsconfig) = tsconfigs. get ( path) {
159+ return Ok ( Arc :: clone ( tsconfig) ) ;
201160 }
202161 let meta = self . fs . metadata ( path) . ok ( ) ;
203162 let tsconfig_path = if meta. is_some_and ( |m| m. is_file ) {
@@ -219,14 +178,26 @@ impl<Fs: FileSystem> Cache for FsCache<Fs> {
219178 } ) ?;
220179 callback ( & mut tsconfig) ?;
221180 let tsconfig = Arc :: new ( tsconfig. build ( ) ) ;
222- self . tsconfigs . insert ( path. to_path_buf ( ) , Arc :: clone ( & tsconfig) ) ;
181+ tsconfigs. insert ( path. to_path_buf ( ) , Arc :: clone ( & tsconfig) ) ;
223182 Ok ( tsconfig)
224183 }
225184}
226185
227186impl < Fs : FileSystem > FsCache < Fs > {
228187 pub fn new ( fs : Fs ) -> Self {
229- Self { fs, paths : DashSet :: default ( ) , tsconfigs : DashMap :: default ( ) }
188+ Self {
189+ fs,
190+ paths : HashSet :: builder ( )
191+ . hasher ( BuildHasherDefault :: default ( ) )
192+ . resize_mode ( papaya:: ResizeMode :: Blocking )
193+ . collector ( seize:: Collector :: new ( ) . epoch_frequency ( None ) )
194+ . build ( ) ,
195+ tsconfigs : HashMap :: builder ( )
196+ . hasher ( BuildHasherDefault :: default ( ) )
197+ . resize_mode ( papaya:: ResizeMode :: Blocking )
198+ . collector ( seize:: Collector :: new ( ) . epoch_frequency ( None ) )
199+ . build ( ) ,
200+ }
230201 }
231202
232203 /// Returns the canonical path, resolving all symbolic links.
@@ -479,6 +450,29 @@ impl PartialEq for FsCachedPath {
479450
480451impl Eq for FsCachedPath { }
481452
453+ struct BorrowedCachedPath < ' a > {
454+ hash : u64 ,
455+ path : & ' a Path ,
456+ }
457+
458+ impl Equivalent < FsCachedPath > for BorrowedCachedPath < ' _ > {
459+ fn equivalent ( & self , other : & FsCachedPath ) -> bool {
460+ self . path . as_os_str ( ) == other. path . as_os_str ( )
461+ }
462+ }
463+
464+ impl Hash for BorrowedCachedPath < ' _ > {
465+ fn hash < H : Hasher > ( & self , state : & mut H ) {
466+ self . hash . hash ( state) ;
467+ }
468+ }
469+
470+ impl PartialEq for BorrowedCachedPath < ' _ > {
471+ fn eq ( & self , other : & Self ) -> bool {
472+ self . path . as_os_str ( ) == other. path . as_os_str ( )
473+ }
474+ }
475+
482476/// Since the cache key is memoized, use an identity hasher
483477/// to avoid double cache.
484478#[ derive( Default ) ]
0 commit comments