@@ -115,7 +115,7 @@ use crate::pgdatadir_mapping::{
115
115
use crate :: task_mgr:: TaskKind ;
116
116
use crate :: tenant:: config:: AttachmentMode ;
117
117
use crate :: tenant:: gc_result:: GcResult ;
118
- use crate :: tenant:: layer_map:: { LayerMap , SearchResult } ;
118
+ use crate :: tenant:: layer_map:: LayerMap ;
119
119
use crate :: tenant:: metadata:: TimelineMetadata ;
120
120
use crate :: tenant:: storage_layer:: delta_layer:: DeltaEntry ;
121
121
use crate :: tenant:: storage_layer:: inmemory_layer:: IndexEntry ;
@@ -4104,12 +4104,6 @@ impl Timeline {
4104
4104
cancel : & CancellationToken ,
4105
4105
ctx : & RequestContext ,
4106
4106
) -> 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
-
4113
4107
// Prevent GC from progressing while visiting the current timeline.
4114
4108
// If we are GC-ing because a new image layer was added while traversing
4115
4109
// the timeline, then it will remove layers that are required for fulfilling
@@ -4120,11 +4114,44 @@ impl Timeline {
4120
4114
// See `compaction::compact_with_gc` for why we need this.
4121
4115
let _guard = timeline. gc_compaction_layer_update_lock . read ( ) . await ;
4122
4116
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 ( ) {
4124
4131
if cancel. is_cancelled ( ) {
4125
4132
return Err ( GetVectoredError :: Cancelled ) ;
4126
4133
}
4127
4134
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
+
4128
4155
let ( keys_done_last_step, keys_with_image_coverage) =
4129
4156
reconstruct_state. consume_done_keys ( ) ;
4130
4157
unmapped_keyspace. remove_overlapping_with ( & keys_done_last_step) ;
@@ -4135,31 +4162,15 @@ impl Timeline {
4135
4162
image_covered_keyspace. add_range ( keys_with_image_coverage) ;
4136
4163
}
4137
4164
4165
+ // Query the layer map for the next layers to read.
4166
+ //
4138
4167
// Do not descent any further if the last layer we visited
4139
4168
// completed all keys in the keyspace it inspected. This is not
4140
4169
// required for correctness, but avoids visiting extra layers
4141
4170
// which turns out to be a perf bottleneck in some cases.
4142
4171
if !unmapped_keyspace. is_empty ( ) {
4143
4172
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) ?;
4163
4174
4164
4175
// It's safe to drop the layer map lock after planning the next round of reads.
4165
4176
// The fringe keeps readable handles for the layers which are safe to read even
@@ -4173,28 +4184,6 @@ impl Timeline {
4173
4184
// at two different time points.
4174
4185
drop ( guard) ;
4175
4186
}
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
- }
4198
4187
}
4199
4188
4200
4189
Ok ( TimelineVisitOutcome {
0 commit comments