@@ -115,7 +115,7 @@ use crate::pgdatadir_mapping::{
115115use crate :: task_mgr:: TaskKind ;
116116use crate :: tenant:: config:: AttachmentMode ;
117117use crate :: tenant:: gc_result:: GcResult ;
118- use crate :: tenant:: layer_map:: { LayerMap , SearchResult } ;
118+ use crate :: tenant:: layer_map:: LayerMap ;
119119use crate :: tenant:: metadata:: TimelineMetadata ;
120120use crate :: tenant:: storage_layer:: delta_layer:: DeltaEntry ;
121121use crate :: tenant:: storage_layer:: inmemory_layer:: IndexEntry ;
@@ -4104,12 +4104,6 @@ impl Timeline {
41044104 cancel : & CancellationToken ,
41054105 ctx : & RequestContext ,
41064106 ) -> Result < TimelineVisitOutcome , GetVectoredError > {
4107- let mut unmapped_keyspace = keyspace. clone ( ) ;
4108- let mut fringe = LayerFringe :: new ( ) ;
4109-
4110- let mut completed_keyspace = KeySpace :: default ( ) ;
4111- let mut image_covered_keyspace = KeySpaceRandomAccum :: new ( ) ;
4112-
41134107 // Prevent GC from progressing while visiting the current timeline.
41144108 // If we are GC-ing because a new image layer was added while traversing
41154109 // the timeline, then it will remove layers that are required for fulfilling
@@ -4120,11 +4114,44 @@ impl Timeline {
41204114 // See `compaction::compact_with_gc` for why we need this.
41214115 let _guard = timeline. gc_compaction_layer_update_lock . read ( ) . await ;
41224116
4123- loop {
4117+ // Initialize the fringe
4118+ let mut fringe = {
4119+ let mut fringe = LayerFringe :: new ( ) ;
4120+
4121+ let guard = timeline. layers . read ( ) . await ;
4122+ guard. update_search_fringe ( & keyspace, cont_lsn, & mut fringe) ?;
4123+
4124+ fringe
4125+ } ;
4126+
4127+ let mut completed_keyspace = KeySpace :: default ( ) ;
4128+ let mut image_covered_keyspace = KeySpaceRandomAccum :: new ( ) ;
4129+
4130+ while let Some ( ( layer_to_read, keyspace_to_read, lsn_range) ) = fringe. next_layer ( ) {
41244131 if cancel. is_cancelled ( ) {
41254132 return Err ( GetVectoredError :: Cancelled ) ;
41264133 }
41274134
4135+ if let Some ( ref mut read_path) = reconstruct_state. read_path {
4136+ read_path. record_layer_visit ( & layer_to_read, & keyspace_to_read, & lsn_range) ;
4137+ }
4138+
4139+ // Visit the layer and plan IOs for it
4140+ let next_cont_lsn = lsn_range. start ;
4141+ layer_to_read
4142+ . get_values_reconstruct_data (
4143+ keyspace_to_read. clone ( ) ,
4144+ lsn_range,
4145+ reconstruct_state,
4146+ ctx,
4147+ )
4148+ . await ?;
4149+
4150+ let mut unmapped_keyspace = keyspace_to_read;
4151+ cont_lsn = next_cont_lsn;
4152+
4153+ reconstruct_state. on_layer_visited ( & layer_to_read) ;
4154+
41284155 let ( keys_done_last_step, keys_with_image_coverage) =
41294156 reconstruct_state. consume_done_keys ( ) ;
41304157 unmapped_keyspace. remove_overlapping_with ( & keys_done_last_step) ;
@@ -4135,31 +4162,15 @@ impl Timeline {
41354162 image_covered_keyspace. add_range ( keys_with_image_coverage) ;
41364163 }
41374164
4165+ // Query the layer map for the next layers to read.
4166+ //
41384167 // Do not descent any further if the last layer we visited
41394168 // completed all keys in the keyspace it inspected. This is not
41404169 // required for correctness, but avoids visiting extra layers
41414170 // which turns out to be a perf bottleneck in some cases.
41424171 if !unmapped_keyspace. is_empty ( ) {
41434172 let guard = timeline. layers . read ( ) . await ;
4144- let layers = guard. layer_map ( ) ?;
4145-
4146- for range in unmapped_keyspace. ranges . iter ( ) {
4147- let results = layers. range_search ( range. clone ( ) , cont_lsn) ;
4148-
4149- results
4150- . found
4151- . into_iter ( )
4152- . map ( |( SearchResult { layer, lsn_floor } , keyspace_accum) | {
4153- (
4154- guard. upgrade ( layer) ,
4155- keyspace_accum. to_keyspace ( ) ,
4156- lsn_floor..cont_lsn,
4157- )
4158- } )
4159- . for_each ( |( layer, keyspace, lsn_range) | {
4160- fringe. update ( layer, keyspace, lsn_range)
4161- } ) ;
4162- }
4173+ guard. update_search_fringe ( & unmapped_keyspace, cont_lsn, & mut fringe) ?;
41634174
41644175 // It's safe to drop the layer map lock after planning the next round of reads.
41654176 // The fringe keeps readable handles for the layers which are safe to read even
@@ -4173,28 +4184,6 @@ impl Timeline {
41734184 // at two different time points.
41744185 drop ( guard) ;
41754186 }
4176-
4177- if let Some ( ( layer_to_read, keyspace_to_read, lsn_range) ) = fringe. next_layer ( ) {
4178- if let Some ( ref mut read_path) = reconstruct_state. read_path {
4179- read_path. record_layer_visit ( & layer_to_read, & keyspace_to_read, & lsn_range) ;
4180- }
4181- let next_cont_lsn = lsn_range. start ;
4182- layer_to_read
4183- . get_values_reconstruct_data (
4184- keyspace_to_read. clone ( ) ,
4185- lsn_range,
4186- reconstruct_state,
4187- ctx,
4188- )
4189- . await ?;
4190-
4191- unmapped_keyspace = keyspace_to_read;
4192- cont_lsn = next_cont_lsn;
4193-
4194- reconstruct_state. on_layer_visited ( & layer_to_read) ;
4195- } else {
4196- break ;
4197- }
41984187 }
41994188
42004189 Ok ( TimelineVisitOutcome {
0 commit comments