@@ -71,13 +71,9 @@ use crate::core::{PackageId, SourceId, Summary};
71
71
use crate :: sources:: registry:: { RegistryData , RegistryPackage , INDEX_V_MAX } ;
72
72
use crate :: util:: interning:: InternedString ;
73
73
use crate :: util:: { internal, CargoResult , Config , Filesystem , OptVersionReq , ToSemver } ;
74
- use anyhow:: bail;
75
- use cargo_util:: paths;
76
- use log:: { debug, info} ;
74
+ use once_cell:: sync:: OnceCell ;
77
75
use semver:: Version ;
78
76
use std:: collections:: { HashMap , HashSet } ;
79
- use std:: convert:: TryInto ;
80
- use std:: fs;
81
77
use std:: path:: Path ;
82
78
use std:: str;
83
79
@@ -322,14 +318,14 @@ impl<'cfg> RegistryIndex<'cfg> {
322
318
move |maybe| match maybe. parse ( config, raw_data, source_id) {
323
319
Ok ( summary) => Some ( summary) ,
324
320
Err ( e) => {
325
- info ! ( "failed to parse `{}` registry package: {}" , name, e) ;
321
+ log :: info!( "failed to parse `{}` registry package: {}" , name, e) ;
326
322
None
327
323
}
328
324
} ,
329
325
)
330
326
. filter ( move |is| {
331
327
if is. v > max_version {
332
- debug ! (
328
+ log :: debug!(
333
329
"unsupported schema version {} ({} {})" ,
334
330
is. v,
335
331
is. summary. name( ) ,
@@ -369,32 +365,29 @@ impl<'cfg> RegistryIndex<'cfg> {
369
365
370
366
// See module comment in `registry/mod.rs` for why this is structured
371
367
// the way it is.
372
- let fs_name = name
368
+ let pkg_name = name
373
369
. chars ( )
374
370
. flat_map ( |c| c. to_lowercase ( ) )
375
371
. collect :: < String > ( ) ;
376
- let raw_path = match fs_name. len ( ) {
377
- 1 => format ! ( "1/{}" , fs_name) ,
378
- 2 => format ! ( "2/{}" , fs_name) ,
379
- 3 => format ! ( "3/{}/{}" , & fs_name[ ..1 ] , fs_name) ,
380
- _ => format ! ( "{}/{}/{}" , & fs_name[ 0 ..2 ] , & fs_name[ 2 ..4 ] , fs_name) ,
381
- } ;
372
+
373
+ static DB : OnceCell < sled:: Db > = OnceCell :: new ( ) ;
374
+ let db = index_version. and_then ( |v| {
375
+ use sled:: { Config , Mode } ;
376
+ let name = |v| format ! ( "{}-{}-{}.sled" , CURRENT_CACHE_VERSION , INDEX_V_MAX , v) ;
377
+ let path = cache_root. join ( & name ( v) ) ;
378
+ DB . get_or_try_init ( || Config :: new ( ) . mode ( Mode :: HighThroughput ) . path ( path) . open ( ) )
379
+ . map_err ( |e| log:: debug!( "failed to open registry db from {:?}: {}" , name( v) , e) )
380
+ . ok ( )
381
+ } ) ;
382
382
383
383
// Attempt to handle misspellings by searching for a chain of related
384
384
// names to the original `raw_path` name. Only return summaries
385
385
// associated with the first hit, however. The resolver will later
386
386
// reject any candidates that have the wrong name, and with this it'll
387
387
// along the way produce helpful "did you mean?" suggestions.
388
- for path in UncanonicalizedIter :: new ( & raw_path) . take ( 1024 ) {
389
- let summaries = Summaries :: parse (
390
- index_version. as_deref ( ) ,
391
- root,
392
- & cache_root,
393
- path. as_ref ( ) ,
394
- self . source_id ,
395
- load,
396
- self . config ,
397
- ) ?;
388
+ for pkg_name in UncanonicalizedIter :: new ( & pkg_name) . take ( 1024 ) {
389
+ let summaries =
390
+ Summaries :: parse ( root, db, & pkg_name, self . source_id , load, self . config ) ?;
398
391
if let Some ( summaries) = summaries {
399
392
self . summaries_cache . insert ( name, summaries) ;
400
393
return Ok ( self . summaries_cache . get_mut ( & name) . unwrap ( ) ) ;
@@ -520,46 +513,56 @@ impl Summaries {
520
513
/// * `load` - the actual index implementation which may be very slow to
521
514
/// call. We avoid this if we can.
522
515
pub fn parse (
523
- index_version : Option < & str > ,
524
516
root : & Path ,
525
- cache_root : & Path ,
526
- relative : & Path ,
517
+ db : Option < & sled :: Db > ,
518
+ pkg_name : & str ,
527
519
source_id : SourceId ,
528
520
load : & mut dyn RegistryData ,
529
521
config : & Config ,
530
522
) -> CargoResult < Option < Summaries > > {
531
523
// First up, attempt to load the cache. This could fail for all manner
532
524
// of reasons, but consider all of them non-fatal and just log their
533
525
// occurrence in case anyone is debugging anything.
534
- let cache_path = cache_root. join ( relative) ;
535
526
let mut cache_contents = None ;
536
- if let Some ( index_version) = index_version {
537
- match fs:: read ( & cache_path) {
538
- Ok ( contents) => match Summaries :: parse_cache ( contents, index_version) {
527
+
528
+ if let Some ( db) = db {
529
+ match db. get ( pkg_name) {
530
+ Err ( e) => log:: debug!( "cache missing for {:?} error: {}" , pkg_name, e) ,
531
+ Ok ( None ) => log:: debug!( "cache missing for {:?} in db" , pkg_name) ,
532
+ Ok ( Some ( contents) ) => match Summaries :: parse_cache ( contents. to_vec ( ) ) {
539
533
Ok ( s) => {
540
- log:: debug!( "fast path for registry cache of {:?}" , relative ) ;
534
+ log:: debug!( "fast path for registry cache of {:?}" , pkg_name ) ;
541
535
if cfg ! ( debug_assertions) {
542
536
cache_contents = Some ( s. raw_data ) ;
543
537
} else {
544
538
return Ok ( Some ( s) ) ;
545
539
}
546
540
}
547
541
Err ( e) => {
548
- log:: debug!( "failed to parse {:?} cache: {}" , relative , e) ;
542
+ log:: debug!( "failed to parse {:?} cache: {}" , pkg_name , e) ;
549
543
}
550
544
} ,
551
- Err ( e) => log:: debug!( "cache missing for {:?} error: {}" , relative, e) ,
552
545
}
553
546
}
554
547
555
548
// This is the fallback path where we actually talk to libgit2 to load
556
549
// information. Here we parse every single line in the index (as we need
557
550
// to find the versions)
558
- log:: debug!( "slow path for {:?}" , relative ) ;
551
+ log:: debug!( "slow path for {:?}" , pkg_name ) ;
559
552
let mut ret = Summaries :: default ( ) ;
560
553
let mut hit_closure = false ;
561
554
let mut cache_bytes = None ;
562
- let err = load. load ( root, relative, & mut |contents| {
555
+
556
+ // See module comment in `registry/mod.rs` for why this is structured
557
+ // the way it is.
558
+ let relative = match pkg_name. len ( ) {
559
+ 1 => format ! ( "1/{}" , pkg_name) ,
560
+ 2 => format ! ( "2/{}" , pkg_name) ,
561
+ 3 => format ! ( "3/{}/{}" , & pkg_name[ ..1 ] , pkg_name) ,
562
+ _ => format ! ( "{}/{}/{}" , & pkg_name[ 0 ..2 ] , & pkg_name[ 2 ..4 ] , pkg_name) ,
563
+ } ;
564
+
565
+ let err = load. load ( root, relative. as_ref ( ) , & mut |contents| {
563
566
ret. raw_data = contents. to_vec ( ) ;
564
567
let mut cache = SummariesCache :: default ( ) ;
565
568
hit_closure = true ;
@@ -580,16 +583,16 @@ impl Summaries {
580
583
// entries in the cache preventing those newer
581
584
// versions from reading them (that is, until the
582
585
// cache is rebuilt).
583
- log:: info!( "failed to parse {:?} registry package: {}" , relative , e) ;
586
+ log:: info!( "failed to parse {:?} registry package: {}" , pkg_name , e) ;
584
587
continue ;
585
588
}
586
589
} ;
587
590
let version = summary. summary . package_id ( ) . version ( ) . clone ( ) ;
588
591
cache. versions . push ( ( version. clone ( ) , line) ) ;
589
592
ret. versions . insert ( version, summary. into ( ) ) ;
590
593
}
591
- if let Some ( index_version ) = index_version {
592
- cache_bytes = Some ( cache. serialize ( index_version ) ) ;
594
+ if db . is_some ( ) {
595
+ cache_bytes = Some ( cache. serialize ( ) ) ;
593
596
}
594
597
Ok ( ( ) )
595
598
} ) ;
@@ -624,13 +627,9 @@ impl Summaries {
624
627
//
625
628
// This is opportunistic so we ignore failure here but are sure to log
626
629
// something in case of error.
627
- if let Some ( cache_bytes) = cache_bytes {
628
- if paths:: create_dir_all ( cache_path. parent ( ) . unwrap ( ) ) . is_ok ( ) {
629
- let path = Filesystem :: new ( cache_path. clone ( ) ) ;
630
- config. assert_package_cache_locked ( & path) ;
631
- if let Err ( e) = fs:: write ( cache_path, cache_bytes) {
632
- log:: info!( "failed to write cache: {}" , e) ;
633
- }
630
+ if let ( Some ( cache_bytes) , Some ( db) ) = ( cache_bytes, db) {
631
+ if let Err ( e) = db. insert ( pkg_name, cache_bytes) {
632
+ log:: info!( "failed to write cache for {:?}: {}" , pkg_name, e) ;
634
633
}
635
634
}
636
635
@@ -639,8 +638,8 @@ impl Summaries {
639
638
640
639
/// Parses an open `File` which represents information previously cached by
641
640
/// Cargo.
642
- pub fn parse_cache ( contents : Vec < u8 > , last_index_update : & str ) -> CargoResult < Summaries > {
643
- let cache = SummariesCache :: parse ( & contents, last_index_update ) ?;
641
+ pub fn parse_cache ( contents : Vec < u8 > ) -> CargoResult < Summaries > {
642
+ let cache = SummariesCache :: parse ( & contents) ?;
644
643
let mut ret = Summaries :: default ( ) ;
645
644
for ( version, summary) in cache. versions {
646
645
let ( start, end) = subslice_bounds ( & contents, summary) ;
@@ -701,43 +700,13 @@ impl Summaries {
701
700
// the index shouldn't allow these, but unfortunately crates.io doesn't
702
701
// check it.
703
702
704
- const CURRENT_CACHE_VERSION : u8 = 3 ;
703
+ pub ( crate ) const CURRENT_CACHE_VERSION : u8 = 3 ;
705
704
706
705
impl < ' a > SummariesCache < ' a > {
707
- fn parse ( data : & ' a [ u8 ] , last_index_update : & str ) -> CargoResult < SummariesCache < ' a > > {
706
+ fn parse ( data : & ' a [ u8 ] ) -> CargoResult < SummariesCache < ' a > > {
708
707
// NB: keep this method in sync with `serialize` below
709
- let ( first_byte, rest) = data
710
- . split_first ( )
711
- . ok_or_else ( || anyhow:: format_err!( "malformed cache" ) ) ?;
712
- if * first_byte != CURRENT_CACHE_VERSION {
713
- bail ! ( "looks like a different Cargo's cache, bailing out" ) ;
714
- }
715
- let index_v_bytes = rest
716
- . get ( ..4 )
717
- . ok_or_else ( || anyhow:: anyhow!( "cache expected 4 bytes for index version" ) ) ?;
718
- let index_v = u32:: from_le_bytes ( index_v_bytes. try_into ( ) . unwrap ( ) ) ;
719
- if index_v != INDEX_V_MAX {
720
- bail ! (
721
- "index format version {} doesn't match the version I know ({})" ,
722
- index_v,
723
- INDEX_V_MAX
724
- ) ;
725
- }
726
- let rest = & rest[ 4 ..] ;
727
-
728
- let mut iter = split ( rest, 0 ) ;
729
- if let Some ( update) = iter. next ( ) {
730
- if update != last_index_update. as_bytes ( ) {
731
- bail ! (
732
- "cache out of date: current index ({}) != cache ({})" ,
733
- last_index_update,
734
- str :: from_utf8( update) ?,
735
- )
736
- }
737
- } else {
738
- bail ! ( "malformed file" ) ;
739
- }
740
708
let mut ret = SummariesCache :: default ( ) ;
709
+ let mut iter = split ( data, 0 ) ;
741
710
while let Some ( version) = iter. next ( ) {
742
711
let version = str:: from_utf8 ( version) ?;
743
712
let version = Version :: parse ( version) ?;
@@ -747,18 +716,14 @@ impl<'a> SummariesCache<'a> {
747
716
Ok ( ret)
748
717
}
749
718
750
- fn serialize ( & self , index_version : & str ) -> Vec < u8 > {
719
+ fn serialize ( & self ) -> Vec < u8 > {
751
720
// NB: keep this method in sync with `parse` above
752
721
let size = self
753
722
. versions
754
723
. iter ( )
755
- . map ( |( _version, data) | ( 10 + data. len ( ) ) )
724
+ . map ( |( _version, data) | 10 + data. len ( ) )
756
725
. sum ( ) ;
757
726
let mut contents = Vec :: with_capacity ( size) ;
758
- contents. push ( CURRENT_CACHE_VERSION ) ;
759
- contents. extend ( & u32:: to_le_bytes ( INDEX_V_MAX ) ) ;
760
- contents. extend_from_slice ( index_version. as_bytes ( ) ) ;
761
- contents. push ( 0 ) ;
762
727
for ( version, data) in self . versions . iter ( ) {
763
728
contents. extend_from_slice ( version. to_string ( ) . as_bytes ( ) ) ;
764
729
contents. push ( 0 ) ;
0 commit comments