67
67
//! hopefully those are more obvious inline in the code itself.
68
68
69
69
use std:: collections:: { HashMap , HashSet } ;
70
- use std:: fs:: { self , File } ;
71
- use std:: io:: Read ;
70
+ use std:: fs;
72
71
use std:: path:: Path ;
73
72
use std:: str;
74
73
75
- use filetime:: FileTime ;
76
74
use log:: info;
77
75
use semver:: { Version , VersionReq } ;
78
76
@@ -316,7 +314,7 @@ impl<'cfg> RegistryIndex<'cfg> {
316
314
// let root = self.config.assert_package_cache_locked(&self.path);
317
315
let root = load. assert_index_locked ( & self . path ) ;
318
316
let cache_root = root. join ( ".cache" ) ;
319
- let last_index_update = load. last_modified ( ) ; ;
317
+ let index_version = load. current_version ( ) ;
320
318
321
319
// See module comment in `registry/mod.rs` for why this is structured
322
320
// the way it is.
@@ -338,7 +336,7 @@ impl<'cfg> RegistryIndex<'cfg> {
338
336
// along the way produce helpful "did you mean?" suggestions.
339
337
for path in UncanonicalizedIter :: new ( & raw_path) . take ( 1024 ) {
340
338
let summaries = Summaries :: parse (
341
- last_index_update ,
339
+ index_version . as_ref ( ) . map ( |s| & * * s ) ,
342
340
& root,
343
341
& cache_root,
344
342
path. as_ref ( ) ,
@@ -471,7 +469,7 @@ impl Summaries {
471
469
/// * `load` - the actual index implementation which may be very slow to
472
470
/// call. We avoid this if we can.
473
471
pub fn parse (
474
- last_index_update : Option < FileTime > ,
472
+ index_version : Option < & str > ,
475
473
root : & Path ,
476
474
cache_root : & Path ,
477
475
relative : & Path ,
@@ -483,24 +481,18 @@ impl Summaries {
483
481
// of reasons, but consider all of them non-fatal and just log their
484
482
// occurrence in case anyone is debugging anything.
485
483
let cache_path = cache_root. join ( relative) ;
486
- if let Some ( last_index_update) = last_index_update {
487
- match File :: open ( & cache_path) {
488
- Ok ( file) => {
489
- let metadata = file. metadata ( ) ?;
490
- let cache_mtime = FileTime :: from_last_modification_time ( & metadata) ;
491
- if cache_mtime > last_index_update {
492
- log:: debug!( "cache for {:?} is fresh" , relative) ;
493
- match Summaries :: parse_cache ( & file, & metadata) {
494
- Ok ( s) => return Ok ( Some ( s) ) ,
495
- Err ( e) => {
496
- log:: debug!( "failed to parse {:?} cache: {}" , relative, e) ;
497
- }
498
- }
499
- } else {
500
- log:: debug!( "cache for {:?} is out of date" , relative) ;
484
+ if let Some ( index_version) = index_version {
485
+ match fs:: read ( & cache_path) {
486
+ Ok ( contents) => match Summaries :: parse_cache ( contents, index_version) {
487
+ Ok ( s) => {
488
+ log:: debug!( "fast path for registry cache of {:?}" , relative) ;
489
+ return Ok ( Some ( s) )
501
490
}
502
- }
503
- Err ( e) => log:: debug!( "cache for {:?} error: {}" , relative, e) ,
491
+ Err ( e) => {
492
+ log:: debug!( "failed to parse {:?} cache: {}" , relative, e) ;
493
+ }
494
+ } ,
495
+ Err ( e) => log:: debug!( "cache missing for {:?} error: {}" , relative, e) ,
504
496
}
505
497
}
506
498
@@ -510,7 +502,7 @@ impl Summaries {
510
502
log:: debug!( "slow path for {:?}" , relative) ;
511
503
let mut ret = Summaries :: default ( ) ;
512
504
let mut hit_closure = false ;
513
- let mut cache_bytes = Vec :: new ( ) ;
505
+ let mut cache_bytes = None ;
514
506
let err = load. load ( root, relative, & mut |contents| {
515
507
ret. raw_data = contents. to_vec ( ) ;
516
508
let mut cache = SummariesCache :: default ( ) ;
@@ -535,7 +527,9 @@ impl Summaries {
535
527
ret. versions . insert ( version, summary. into ( ) ) ;
536
528
start = end + 1 ;
537
529
}
538
- cache_bytes = cache. serialize ( ) ;
530
+ if let Some ( index_version) = index_version {
531
+ cache_bytes = Some ( cache. serialize ( index_version) ) ;
532
+ }
539
533
Ok ( ( ) )
540
534
} ) ;
541
535
@@ -553,26 +547,22 @@ impl Summaries {
553
547
//
554
548
// This is opportunistic so we ignore failure here but are sure to log
555
549
// something in case of error.
556
- //
557
- // Note that we also skip this when `last_index_update` is `None` because it
558
- // means we can't handle the cache anyway.
559
- if last_index_update. is_some ( ) && fs:: create_dir_all ( cache_path. parent ( ) . unwrap ( ) ) . is_ok ( ) {
560
- let path = Filesystem :: new ( cache_path. clone ( ) ) ;
561
- config. assert_package_cache_locked ( & path) ;
562
- if let Err ( e) = fs:: write ( cache_path, cache_bytes) {
563
- log:: info!( "failed to write cache: {}" , e) ;
550
+ if let Some ( cache_bytes) = cache_bytes {
551
+ if fs:: create_dir_all ( cache_path. parent ( ) . unwrap ( ) ) . is_ok ( ) {
552
+ let path = Filesystem :: new ( cache_path. clone ( ) ) ;
553
+ config. assert_package_cache_locked ( & path) ;
554
+ if let Err ( e) = fs:: write ( cache_path, cache_bytes) {
555
+ log:: info!( "failed to write cache: {}" , e) ;
556
+ }
564
557
}
565
558
}
566
559
Ok ( Some ( ret) )
567
560
}
568
561
569
562
/// Parses an open `File` which represents information previously cached by
570
563
/// Cargo.
571
- pub fn parse_cache ( mut file : & File , meta : & fs:: Metadata ) -> CargoResult < Summaries > {
572
- let mut contents = Vec :: new ( ) ;
573
- contents. reserve ( meta. len ( ) as usize + 1 ) ;
574
- file. read_to_end ( & mut contents) ?;
575
- let cache = SummariesCache :: parse ( & contents) ?;
564
+ pub fn parse_cache ( contents : Vec < u8 > , last_index_update : & str ) -> CargoResult < Summaries > {
565
+ let cache = SummariesCache :: parse ( & contents, last_index_update) ?;
576
566
let mut ret = Summaries :: default ( ) ;
577
567
for ( version, summary) in cache. versions {
578
568
let ( start, end) = subslice_bounds ( & contents, summary) ;
@@ -614,7 +604,7 @@ impl Summaries {
614
604
const CURRENT_CACHE_VERSION : u8 = 1 ;
615
605
616
606
impl < ' a > SummariesCache < ' a > {
617
- fn parse ( data : & ' a [ u8 ] ) -> CargoResult < SummariesCache < ' a > > {
607
+ fn parse ( data : & ' a [ u8 ] , last_index_update : & str ) -> CargoResult < SummariesCache < ' a > > {
618
608
// NB: keep this method in sync with `serialize` below
619
609
let ( first_byte, rest) = data
620
610
. split_first ( )
@@ -624,6 +614,19 @@ impl<'a> SummariesCache<'a> {
624
614
}
625
615
let mut iter = memchr:: Memchr :: new ( 0 , rest) ;
626
616
let mut start = 0 ;
617
+ if let Some ( end) = iter. next ( ) {
618
+ let update = & rest[ start..end] ;
619
+ if update != last_index_update. as_bytes ( ) {
620
+ failure:: bail!(
621
+ "cache out of date: current index ({}) != cache ({})" ,
622
+ last_index_update,
623
+ str :: from_utf8( update) ?,
624
+ )
625
+ }
626
+ start = end + 1 ;
627
+ } else {
628
+ failure:: bail!( "malformed file" ) ;
629
+ }
627
630
let mut ret = SummariesCache :: default ( ) ;
628
631
while let Some ( version_end) = iter. next ( ) {
629
632
let version = & rest[ start..version_end] ;
@@ -637,7 +640,7 @@ impl<'a> SummariesCache<'a> {
637
640
Ok ( ret)
638
641
}
639
642
640
- fn serialize ( & self ) -> Vec < u8 > {
643
+ fn serialize ( & self , index_version : & str ) -> Vec < u8 > {
641
644
// NB: keep this method in sync with `parse` above
642
645
let size = self
643
646
. versions
@@ -646,6 +649,8 @@ impl<'a> SummariesCache<'a> {
646
649
. sum ( ) ;
647
650
let mut contents = Vec :: with_capacity ( size) ;
648
651
contents. push ( CURRENT_CACHE_VERSION ) ;
652
+ contents. extend_from_slice ( index_version. as_bytes ( ) ) ;
653
+ contents. push ( 0 ) ;
649
654
for ( version, data) in self . versions . iter ( ) {
650
655
contents. extend_from_slice ( version. to_string ( ) . as_bytes ( ) ) ;
651
656
contents. push ( 0 ) ;
0 commit comments