diff --git a/pageserver/src/tenant/layer_map/historic_layer_coverage.rs b/pageserver/src/tenant/layer_map/historic_layer_coverage.rs index 5150f23a06..15c748f651 100644 --- a/pageserver/src/tenant/layer_map/historic_layer_coverage.rs +++ b/pageserver/src/tenant/layer_map/historic_layer_coverage.rs @@ -398,6 +398,16 @@ pub struct BufferedHistoricLayerCoverage { /// All current layers. This is not used for search. Only to make rebuilds easier. layers: BTreeMap, + + /// Redundant layers are ones that are completely covered by a union of other layers. + /// If two layers are identical only one of them will be marked as redundant, such that + /// it is always safe to remove all redundant layers without seeing any difference in + /// results. + /// + /// Redundant layers can show up if the pageserver dies during compaction, after + /// creating some L1 layers but before deleting the L0 layers. In this case we'd rather + /// notice the redundant L0 layers than recreate the L1 layer, or do something worse. + redundant_layers: BTreeMap, } impl std::fmt::Debug for BufferedHistoricLayerCoverage { @@ -421,6 +431,7 @@ impl BufferedHistoricLayerCoverage { historic_coverage: HistoricLayerCoverage::::new(), buffer: BTreeMap::new(), layers: BTreeMap::new(), + redundant_layers: BTreeMap::new(), } } @@ -501,6 +512,7 @@ impl BufferedHistoricLayerCoverage { } None => { self.layers.remove(layer_key); + self.redundant_layers.remove(layer_key); } }; false @@ -511,8 +523,8 @@ impl BufferedHistoricLayerCoverage { self.historic_coverage.trim(&rebuild_since); for (layer_key, layer) in self.layers.range( LayerKey { - lsn: rebuild_since..0, - key: 0..0, + lsn: rebuild_since..u64::MAX, + key: 0..i128::MAX, is_image: false, }.., ) { @@ -521,7 +533,8 @@ impl BufferedHistoricLayerCoverage { num_inserted += 1; if was_noop { - // TODO keep track + println!("Redundant layer {:?}", layer_key); + self.redundant_layers.insert(layer_key.clone(), layer.clone()); } }