@@ -250,7 +250,7 @@ pub struct RegistryClient {
250250 connectivity : Connectivity ,
251251 /// Client HTTP read timeout.
252252 read_timeout : Duration ,
253- /// The flat index entries for each `--find-links`-style index URL.
253+ /// The flat index entries for each `--find-links`-style index URL, with one slot per index .
254254 flat_indexes : Arc < Mutex < FlatIndexCache > > ,
255255 /// The pyx token store to use for persistent credentials.
256256 // TODO(charlie): The token store is only needed for `is_known_url`; can we avoid storing it here?
@@ -459,11 +459,15 @@ impl RegistryClient {
459459 package_name : & PackageName ,
460460 index : & IndexUrl ,
461461 ) -> Result < Vec < FlatIndexEntry > , Error > {
462- // Store the flat index entries in a cache, to avoid redundant fetches. A flat index will
463- // typically contain entries for multiple packages; as such, it's more efficient to cache
464- // the entire index rather than re-fetching it for each package.
465- let mut cache = self . flat_indexes . lock ( ) . await ;
466- if let Some ( entries) = cache. get ( index) {
462+ // Each flat index gets its own slot, so lookups for the same index share a fetch while
463+ // unrelated indexes can proceed concurrently.
464+ let flat_index_slot = {
465+ let mut cache = self . flat_indexes . lock ( ) . await ;
466+ cache. get_or_insert ( index)
467+ } ;
468+ let mut flat_index = flat_index_slot. lock ( ) . await ;
469+
470+ if let Some ( entries) = flat_index. as_ref ( ) {
467471 return Ok ( entries. get ( package_name) . cloned ( ) . unwrap_or_default ( ) ) ;
468472 }
469473
@@ -488,7 +492,7 @@ impl RegistryClient {
488492 . unwrap_or_default ( ) ;
489493
490494 // Write to the cache.
491- cache . insert ( index . clone ( ) , entries_by_package) ;
495+ * flat_index = Some ( entries_by_package) ;
492496
493497 Ok ( package_entries)
494498 }
@@ -1274,25 +1278,22 @@ impl From<IndexStatusCodeDecision> for SimpleMetadataSearchOutcome {
12741278
12751279/// A map from [`IndexUrl`] to [`FlatIndexEntry`] entries found at the given URL, indexed by
12761280/// [`PackageName`].
1277- #[ derive( Default , Debug , Clone ) ]
1278- struct FlatIndexCache ( FxHashMap < IndexUrl , FxHashMap < PackageName , Vec < FlatIndexEntry > > > ) ;
1281+ #[ derive( Default , Debug ) ]
1282+ struct FlatIndexCache ( FxHashMap < IndexUrl , FlatIndexSlot > ) ;
12791283
12801284impl FlatIndexCache {
1281- /// Get the entries for a given index URL.
1282- fn get ( & self , index : & IndexUrl ) -> Option < & FxHashMap < PackageName , Vec < FlatIndexEntry > > > {
1283- self . 0 . get ( index)
1284- }
1285-
1286- /// Insert the entries for a given index URL.
1287- fn insert (
1288- & mut self ,
1289- index : IndexUrl ,
1290- entries : FxHashMap < PackageName , Vec < FlatIndexEntry > > ,
1291- ) -> Option < FxHashMap < PackageName , Vec < FlatIndexEntry > > > {
1292- self . 0 . insert ( index, entries)
1285+ /// Return the per-index slot for this flat index, creating it on first access.
1286+ fn get_or_insert ( & mut self , index : & IndexUrl ) -> FlatIndexSlot {
1287+ self . 0
1288+ . entry ( index. clone ( ) )
1289+ . or_insert_with ( || Arc :: new ( Mutex :: new ( None ) ) )
1290+ . clone ( )
12931291 }
12941292}
12951293
1294+ type FlatIndexEntriesByPackage = FxHashMap < PackageName , Vec < FlatIndexEntry > > ;
1295+ type FlatIndexSlot = Arc < Mutex < Option < FlatIndexEntriesByPackage > > > ;
1296+
12961297#[ derive( Default , Debug , rkyv:: Archive , rkyv:: Deserialize , rkyv:: Serialize ) ]
12971298#[ rkyv( derive( Debug ) ) ]
12981299pub struct VersionFiles {
0 commit comments