From 422310c19b7bd06e16ab6f060d929d2b7abe8c96 Mon Sep 17 00:00:00 2001 From: John Spray Date: Mon, 17 Feb 2025 22:43:36 +0100 Subject: [PATCH] slightly more efficient --- pageserver/src/tenant/layer_map.rs | 14 +++++++++++++- .../tenant/layer_map/historic_layer_coverage.rs | 12 ++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/pageserver/src/tenant/layer_map.rs b/pageserver/src/tenant/layer_map.rs index 2fb76197b7..a67f6785a9 100644 --- a/pageserver/src/tenant/layer_map.rs +++ b/pageserver/src/tenant/layer_map.rs @@ -570,6 +570,10 @@ impl LayerMap { self.historic.iter() } + pub fn riter_historic_layers(&self) -> impl '_ + Iterator> { + self.historic.riter() + } + /// Get a ref counted pointer for the first in memory layer that matches the provided predicate. pub(crate) fn find_in_memory_layer(&self, mut pred: Pred) -> Option> where @@ -900,12 +904,20 @@ impl LayerMap { Ok(()) } + /// Efficiency: this is a single btreemap walk to the end of the map in the common case where + /// we are queried for image layers after the start of an ephemeral layer. In the general case + /// where we are called with some arbitrary LSN, this function is O(N) -- so don't use it like that. pub(crate) fn get_newest_image_after(&self, lsn: Lsn) -> Option> { // TODO: an efficient equivalent, this is a crude placeholder - for layer in self.iter_historic_layers() { + for layer in self.riter_historic_layers() { if !layer.is_delta() && layer.image_layer_lsn() >= lsn { return Some(layer); } + + if layer.lsn_range.start < lsn { + // We are past the layers that could possibly intersect with the requested bound + break; + } } None } diff --git a/pageserver/src/tenant/layer_map/historic_layer_coverage.rs b/pageserver/src/tenant/layer_map/historic_layer_coverage.rs index 136f68bc36..870bb9830f 100644 --- a/pageserver/src/tenant/layer_map/historic_layer_coverage.rs +++ b/pageserver/src/tenant/layer_map/historic_layer_coverage.rs @@ -509,6 +509,18 @@ impl BufferedHistoricLayerCoverage { self.layers.values().cloned() } + /// Iterate all the layers in reverse order (newest LSNs first) + pub fn riter(&self) -> impl '_ + Iterator { + // NOTE we can actually perform this without rebuilding, + // but it's not necessary for now. + if !self.buffer.is_empty() { + panic!("rebuild pls") + } + + // TODO: is cloned() really needed? + self.layers.values().rev().cloned() + } + /// Return a reference to a queryable map, assuming all updates /// have already been processed using self.rebuild() pub fn get(&self) -> anyhow::Result<&HistoricLayerCoverage> {