diff --git a/pageserver/src/layered_repository/delta_layer.rs b/pageserver/src/layered_repository/delta_layer.rs index 950ac56151..4edad28995 100644 --- a/pageserver/src/layered_repository/delta_layer.rs +++ b/pageserver/src/layered_repository/delta_layer.rs @@ -63,6 +63,7 @@ use bookfile::{Book, BookWriter}; use zenith_utils::bin_ser::BeSer; use zenith_utils::lsn::Lsn; +use zenith_utils::ordered_vec::OrderedVec; use super::blob::{read_blob, BlobRange}; @@ -147,7 +148,7 @@ pub struct DeltaLayerInner { page_version_metas: BTreeMap<(u32, Lsn), BlobRange>, /// `relsizes` tracks the size of the relation at different points in time. - relsizes: BTreeMap, + relsizes: OrderedVec, } impl Layer for DeltaLayer { @@ -268,10 +269,10 @@ impl Layer for DeltaLayer { // Scan the BTreeMap backwards, starting from the given entry. let inner = self.load()?; - let mut iter = inner.relsizes.range((Included(&Lsn(0)), Included(&lsn))); + let slice = inner.relsizes.range((Included(&Lsn(0)), Included(&lsn))); let result; - if let Some((_entry_lsn, entry)) = iter.next_back() { + if let Some((_entry_lsn, entry)) = slice.last() { result = *entry; // Use the base image if needed } else if let Some(predecessor) = &self.predecessor { @@ -300,7 +301,7 @@ impl Layer for DeltaLayer { fn unload(&self) -> Result<()> { let mut inner = self.inner.lock().unwrap(); inner.page_version_metas = BTreeMap::new(); - inner.relsizes = BTreeMap::new(); + inner.relsizes = OrderedVec::default(); inner.loaded = false; Ok(()) } @@ -404,7 +405,7 @@ impl DeltaLayer { inner: Mutex::new(DeltaLayerInner { loaded: true, page_version_metas: BTreeMap::new(), - relsizes, + relsizes: OrderedVec::from(relsizes), }), predecessor, }; @@ -442,7 +443,7 @@ impl DeltaLayer { // and relsizes to separate chapter let mut chapter = book.new_chapter(REL_SIZES_CHAPTER); - let buf = BTreeMap::ser(&inner.relsizes)?; + let buf = OrderedVec::ser(&inner.relsizes)?; chapter.write_all(&buf)?; let book = chapter.close()?; @@ -532,7 +533,7 @@ impl DeltaLayer { let page_version_metas = BTreeMap::des(&chapter)?; let chapter = book.read_chapter(REL_SIZES_CHAPTER)?; - let relsizes = BTreeMap::des(&chapter)?; + let relsizes = OrderedVec::des(&chapter)?; debug!("loaded from {}", &path.display()); @@ -564,7 +565,7 @@ impl DeltaLayer { inner: Mutex::new(DeltaLayerInner { loaded: false, page_version_metas: BTreeMap::new(), - relsizes: BTreeMap::new(), + relsizes: OrderedVec::default(), }), predecessor, } @@ -588,7 +589,7 @@ impl DeltaLayer { inner: Mutex::new(DeltaLayerInner { loaded: false, page_version_metas: BTreeMap::new(), - relsizes: BTreeMap::new(), + relsizes: OrderedVec::default(), }), predecessor: None, }) diff --git a/zenith_utils/src/lib.rs b/zenith_utils/src/lib.rs index ca26be5df2..30a3a7a6c0 100644 --- a/zenith_utils/src/lib.rs +++ b/zenith_utils/src/lib.rs @@ -8,6 +8,8 @@ pub mod lsn; /// SeqWait allows waiting for a future sequence number to arrive pub mod seqwait; +pub mod ordered_vec; + // Async version of SeqWait. Currently unused. // pub mod seqwait_async; diff --git a/zenith_utils/src/ordered_vec.rs b/zenith_utils/src/ordered_vec.rs new file mode 100644 index 0000000000..ccede9ce05 --- /dev/null +++ b/zenith_utils/src/ordered_vec.rs @@ -0,0 +1,68 @@ +use std::{ + collections::BTreeMap, + ops::{Bound, RangeBounds}, +}; + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct OrderedVec(Vec<(K, V)>); + +impl Default for OrderedVec { + fn default() -> Self { + Self(Default::default()) + } +} + +impl OrderedVec { + pub fn iter(&self) -> std::slice::Iter<'_, (K, V)> { + self.0.iter() + } + + pub fn range>(&self, range: R) -> &[(K, V)] { + let start_idx = match range.start_bound() { + Bound::Included(key) => match self.0.binary_search_by_key(key, extract_key) { + Ok(idx) => idx, + Err(idx) => idx, + }, + Bound::Excluded(key) => match self.0.binary_search_by_key(key, extract_key) { + Ok(idx) => idx + 1, + Err(idx) => idx, + }, + Bound::Unbounded => 0, + }; + + let end_idx = match range.end_bound() { + Bound::Included(key) => match self.0.binary_search_by_key(key, extract_key) { + Ok(idx) => idx, + Err(idx) => idx + 1, + }, + Bound::Excluded(key) => match self.0.binary_search_by_key(key, extract_key) { + Ok(idx) => idx + 1, + Err(idx) => idx + 1, + }, + Bound::Unbounded => self.0.len(), + }; + + &self.0[start_idx..end_idx] + } +} + +impl From> for OrderedVec { + fn from(map: BTreeMap) -> Self { + let vec: Vec<(K, V)> = map.into_iter().collect(); + + // TODO probably change this + for windows in vec.windows(2) { + let (k1, _data1) = &windows[0]; + let (k2, _data2) = &windows[1]; + debug_assert!(k1 < k2); + } + + OrderedVec(vec) + } +} + +fn extract_key(pair: &(K, V)) -> K { + pair.0 +}