68
68
69
69
use crate :: core:: dependency:: Dependency ;
70
70
use crate :: core:: { PackageId , SourceId , Summary } ;
71
- use crate :: sources:: registry:: { RegistryData , RegistryPackage , INDEX_V_MAX } ;
71
+ use crate :: sources:: registry:: { LoadResponse , RegistryData , RegistryPackage , INDEX_V_MAX } ;
72
72
use crate :: util:: interning:: InternedString ;
73
73
use crate :: util:: { internal, CargoResult , Config , Filesystem , OptVersionReq , ToSemver } ;
74
74
use anyhow:: bail;
@@ -247,6 +247,7 @@ pub struct IndexSummary {
247
247
#[ derive( Default ) ]
248
248
struct SummariesCache < ' a > {
249
249
versions : Vec < ( Version , & ' a [ u8 ] ) > ,
250
+ index_version : & ' a str ,
250
251
}
251
252
252
253
impl < ' cfg > RegistryIndex < ' cfg > {
@@ -358,7 +359,6 @@ impl<'cfg> RegistryIndex<'cfg> {
358
359
359
360
let root = load. assert_index_locked ( & self . path ) ;
360
361
let cache_root = root. join ( ".cache" ) ;
361
- let index_version = load. current_version ( ) ;
362
362
363
363
// See module comment in `registry/mod.rs` for why this is structured
364
364
// the way it is.
@@ -376,7 +376,6 @@ impl<'cfg> RegistryIndex<'cfg> {
376
376
// along the way produce helpful "did you mean?" suggestions.
377
377
for ( i, path) in UncanonicalizedIter :: new ( & raw_path) . take ( 1024 ) . enumerate ( ) {
378
378
let summaries = Summaries :: parse (
379
- index_version. as_deref ( ) ,
380
379
root,
381
380
& cache_root,
382
381
path. as_ref ( ) ,
@@ -559,7 +558,6 @@ impl Summaries {
559
558
/// * `load` - the actual index implementation which may be very slow to
560
559
/// call. We avoid this if we can.
561
560
pub fn parse (
562
- index_version : Option < & str > ,
563
561
root : & Path ,
564
562
cache_root : & Path ,
565
563
relative : & Path ,
@@ -571,88 +569,101 @@ impl Summaries {
571
569
// of reasons, but consider all of them non-fatal and just log their
572
570
// occurrence in case anyone is debugging anything.
573
571
let cache_path = cache_root. join ( relative) ;
574
- let mut cache_contents = None ;
575
- if let Some ( index_version) = index_version {
576
- match fs:: read ( & cache_path) {
577
- Ok ( contents) => match Summaries :: parse_cache ( contents, index_version) {
578
- Ok ( s) => {
579
- log:: debug!( "fast path for registry cache of {:?}" , relative) ;
580
- if cfg ! ( debug_assertions) {
581
- cache_contents = Some ( s. raw_data ) ;
582
- } else {
583
- return Poll :: Ready ( Ok ( Some ( s) ) ) ;
584
- }
585
- }
586
- Err ( e) => {
587
- log:: debug!( "failed to parse {:?} cache: {}" , relative, e) ;
588
- }
589
- } ,
590
- Err ( e) => log:: debug!( "cache missing for {:?} error: {}" , relative, e) ,
591
- }
572
+ let mut cached_summaries = None ;
573
+ let mut index_version = None ;
574
+ match fs:: read ( & cache_path) {
575
+ Ok ( contents) => match Summaries :: parse_cache ( contents) {
576
+ Ok ( ( s, v) ) => {
577
+ cached_summaries = Some ( s) ;
578
+ index_version = Some ( v) ;
579
+ }
580
+ Err ( e) => {
581
+ log:: debug!( "failed to parse {:?} cache: {}" , relative, e) ;
582
+ }
583
+ } ,
584
+ Err ( e) => log:: debug!( "cache missing for {:?} error: {}" , relative, e) ,
592
585
}
593
586
594
- // This is the fallback path where we actually talk to the registry backend to load
595
- // information. Here we parse every single line in the index (as we need
596
- // to find the versions)
597
- log:: debug!( "slow path for {:?}" , relative) ;
587
+ let mut response = load. load ( root, relative, index_version. as_deref ( ) ) ?;
588
+ // In debug builds, perform a second load without the cache so that
589
+ // we can validate that the cache is correct.
590
+ if cfg ! ( debug_assertions) && matches ! ( response, Poll :: Ready ( LoadResponse :: CacheValid ) ) {
591
+ response = load. load ( root, relative, None ) ?;
592
+ }
593
+ let response = match response {
594
+ Poll :: Pending => return Poll :: Pending ,
595
+ Poll :: Ready ( response) => response,
596
+ } ;
597
+
598
+ let mut bytes_to_cache = None ;
599
+ let mut version_to_cache = None ;
598
600
let mut ret = Summaries :: default ( ) ;
599
- let mut hit_closure = false ;
600
- let mut cache_bytes = None ;
601
- let result = load. load ( root, relative, & mut |contents| {
602
- ret. raw_data = contents. to_vec ( ) ;
603
- let mut cache = SummariesCache :: default ( ) ;
604
- hit_closure = true ;
605
- for line in split ( contents, b'\n' ) {
606
- // Attempt forwards-compatibility on the index by ignoring
607
- // everything that we ourselves don't understand, that should
608
- // allow future cargo implementations to break the
609
- // interpretation of each line here and older cargo will simply
610
- // ignore the new lines.
611
- let summary = match IndexSummary :: parse ( config, line, source_id) {
612
- Ok ( summary) => summary,
613
- Err ( e) => {
614
- // This should only happen when there is an index
615
- // entry from a future version of cargo that this
616
- // version doesn't understand. Hopefully, those future
617
- // versions of cargo correctly set INDEX_V_MAX and
618
- // CURRENT_CACHE_VERSION, otherwise this will skip
619
- // entries in the cache preventing those newer
620
- // versions from reading them (that is, until the
621
- // cache is rebuilt).
622
- log:: info!( "failed to parse {:?} registry package: {}" , relative, e) ;
623
- continue ;
624
- }
625
- } ;
626
- let version = summary. summary . package_id ( ) . version ( ) . clone ( ) ;
627
- cache. versions . push ( ( version. clone ( ) , line) ) ;
628
- ret. versions . insert ( version, summary. into ( ) ) ;
601
+ match response {
602
+ LoadResponse :: CacheValid => {
603
+ log:: debug!( "fast path for registry cache of {:?}" , relative) ;
604
+ return Poll :: Ready ( Ok ( cached_summaries) ) ;
629
605
}
630
- if let Some ( index_version) = index_version {
631
- cache_bytes = Some ( cache. serialize ( index_version) ) ;
606
+ LoadResponse :: NotFound => {
607
+ debug_assert ! ( cached_summaries. is_none( ) ) ;
608
+ return Poll :: Ready ( Ok ( None ) ) ;
609
+ }
610
+ LoadResponse :: Data {
611
+ raw_data,
612
+ index_version,
613
+ } => {
614
+ // This is the fallback path where we actually talk to the registry backend to load
615
+ // information. Here we parse every single line in the index (as we need
616
+ // to find the versions)
617
+ log:: debug!( "slow path for {:?}" , relative) ;
618
+ let mut cache = SummariesCache :: default ( ) ;
619
+ ret. raw_data = raw_data;
620
+ for line in split ( & ret. raw_data , b'\n' ) {
621
+ // Attempt forwards-compatibility on the index by ignoring
622
+ // everything that we ourselves don't understand, that should
623
+ // allow future cargo implementations to break the
624
+ // interpretation of each line here and older cargo will simply
625
+ // ignore the new lines.
626
+ let summary = match IndexSummary :: parse ( config, line, source_id) {
627
+ Ok ( summary) => summary,
628
+ Err ( e) => {
629
+ // This should only happen when there is an index
630
+ // entry from a future version of cargo that this
631
+ // version doesn't understand. Hopefully, those future
632
+ // versions of cargo correctly set INDEX_V_MAX and
633
+ // CURRENT_CACHE_VERSION, otherwise this will skip
634
+ // entries in the cache preventing those newer
635
+ // versions from reading them (that is, until the
636
+ // cache is rebuilt).
637
+ log:: info!( "failed to parse {:?} registry package: {}" , relative, e) ;
638
+ continue ;
639
+ }
640
+ } ;
641
+ let version = summary. summary . package_id ( ) . version ( ) . clone ( ) ;
642
+ cache. versions . push ( ( version. clone ( ) , line) ) ;
643
+ ret. versions . insert ( version, summary. into ( ) ) ;
644
+ }
645
+ if let Some ( index_version) = index_version {
646
+ bytes_to_cache = Some ( cache. serialize ( index_version. as_str ( ) ) ) ;
647
+ version_to_cache = Some ( index_version) ;
648
+ }
632
649
}
633
- Ok ( ( ) )
634
- } ) ;
635
-
636
- if result?. is_pending ( ) {
637
- assert ! ( !hit_closure) ;
638
- return Poll :: Pending ;
639
- }
640
-
641
- if !hit_closure {
642
- debug_assert ! ( cache_contents. is_none( ) ) ;
643
- return Poll :: Ready ( Ok ( None ) ) ;
644
650
}
645
651
646
652
// If we've got debug assertions enabled and the cache was previously
647
653
// present and considered fresh this is where the debug assertions
648
654
// actually happens to verify that our cache is indeed fresh and
649
655
// computes exactly the same value as before.
650
- if cfg ! ( debug_assertions) && cache_contents. is_some ( ) && cache_bytes != cache_contents {
656
+ let cache_contents = cached_summaries. as_ref ( ) . map ( |s| & s. raw_data ) ;
657
+ if cfg ! ( debug_assertions)
658
+ && index_version. as_deref ( ) == version_to_cache. as_deref ( )
659
+ && cached_summaries. is_some ( )
660
+ && bytes_to_cache. as_ref ( ) != cache_contents
661
+ {
651
662
panic ! (
652
663
"original cache contents:\n {:?}\n \
653
664
does not equal new cache contents:\n {:?}\n ",
654
665
cache_contents. as_ref( ) . map( |s| String :: from_utf8_lossy( s) ) ,
655
- cache_bytes . as_ref( ) . map( |s| String :: from_utf8_lossy( s) ) ,
666
+ bytes_to_cache . as_ref( ) . map( |s| String :: from_utf8_lossy( s) ) ,
656
667
) ;
657
668
}
658
669
@@ -662,7 +673,7 @@ impl Summaries {
662
673
//
663
674
// This is opportunistic so we ignore failure here but are sure to log
664
675
// something in case of error.
665
- if let Some ( cache_bytes) = cache_bytes {
676
+ if let Some ( cache_bytes) = bytes_to_cache {
666
677
if paths:: create_dir_all ( cache_path. parent ( ) . unwrap ( ) ) . is_ok ( ) {
667
678
let path = Filesystem :: new ( cache_path. clone ( ) ) ;
668
679
config. assert_package_cache_locked ( & path) ;
@@ -677,16 +688,17 @@ impl Summaries {
677
688
678
689
/// Parses an open `File` which represents information previously cached by
679
690
/// Cargo.
680
- pub fn parse_cache ( contents : Vec < u8 > , last_index_update : & str ) -> CargoResult < Summaries > {
681
- let cache = SummariesCache :: parse ( & contents, last_index_update) ?;
691
+ pub fn parse_cache ( contents : Vec < u8 > ) -> CargoResult < ( Summaries , InternedString ) > {
692
+ let cache = SummariesCache :: parse ( & contents) ?;
693
+ let index_version = InternedString :: new ( cache. index_version ) ;
682
694
let mut ret = Summaries :: default ( ) ;
683
695
for ( version, summary) in cache. versions {
684
696
let ( start, end) = subslice_bounds ( & contents, summary) ;
685
697
ret. versions
686
698
. insert ( version, MaybeIndexSummary :: Unparsed { start, end } ) ;
687
699
}
688
700
ret. raw_data = contents;
689
- return Ok ( ret) ;
701
+ return Ok ( ( ret, index_version ) ) ;
690
702
691
703
// Returns the start/end offsets of `inner` with `outer`. Asserts that
692
704
// `inner` is a subslice of `outer`.
@@ -742,7 +754,7 @@ impl Summaries {
742
754
const CURRENT_CACHE_VERSION : u8 = 3 ;
743
755
744
756
impl < ' a > SummariesCache < ' a > {
745
- fn parse ( data : & ' a [ u8 ] , last_index_update : & str ) -> CargoResult < SummariesCache < ' a > > {
757
+ fn parse ( data : & ' a [ u8 ] ) -> CargoResult < SummariesCache < ' a > > {
746
758
// NB: keep this method in sync with `serialize` below
747
759
let ( first_byte, rest) = data
748
760
. split_first ( )
@@ -764,18 +776,13 @@ impl<'a> SummariesCache<'a> {
764
776
let rest = & rest[ 4 ..] ;
765
777
766
778
let mut iter = split ( rest, 0 ) ;
767
- if let Some ( update) = iter. next ( ) {
768
- if update != last_index_update. as_bytes ( ) {
769
- bail ! (
770
- "cache out of date: current index ({}) != cache ({})" ,
771
- last_index_update,
772
- str :: from_utf8( update) ?,
773
- )
774
- }
779
+ let last_index_update = if let Some ( update) = iter. next ( ) {
780
+ str:: from_utf8 ( update) ?
775
781
} else {
776
782
bail ! ( "malformed file" ) ;
777
- }
783
+ } ;
778
784
let mut ret = SummariesCache :: default ( ) ;
785
+ ret. index_version = last_index_update;
779
786
while let Some ( version) = iter. next ( ) {
780
787
let version = str:: from_utf8 ( version) ?;
781
788
let version = Version :: parse ( version) ?;
0 commit comments