From a1f6bbb07659ce0b3c7289c396f59648018aa311 Mon Sep 17 00:00:00 2001 From: Konstantin Knizhnik Date: Wed, 30 Mar 2022 08:16:20 +0300 Subject: [PATCH] Use wrapping multiplication in R-Tree --- Cargo.lock | 1 + pageserver/src/layered_repository.rs | 8 +- .../src/layered_repository/layer_map.rs | 149 +++++++++++++++--- pageserver/src/repository.rs | 12 +- 4 files changed, 140 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index beb94384d0..5dbbd29ae7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1522,6 +1522,7 @@ dependencies = [ "lazy_static", "log", "nix", + "num-traits", "once_cell", "postgres 0.19.1 (git+https://github.com/zenithdb/rust-postgres.git?rev=2949d98df52587d562986aad155dd4e889e408b7)", "postgres-protocol 0.6.1 (git+https://github.com/zenithdb/rust-postgres.git?rev=2949d98df52587d562986aad155dd4e889e408b7)", diff --git a/pageserver/src/layered_repository.rs b/pageserver/src/layered_repository.rs index 4723a4f649..0be556ec28 100644 --- a/pageserver/src/layered_repository.rs +++ b/pageserver/src/layered_repository.rs @@ -2140,7 +2140,7 @@ pub mod tests { let tline = repo.create_empty_timeline(TIMELINE_ID, Lsn(0))?; #[allow(non_snake_case)] - let TEST_KEY: Key = Key::from_hex("110000222233333333444444445500000001").unwrap(); + let TEST_KEY: Key = Key::from_hex("112222222233333333444444445500000001").unwrap(); let writer = tline.writer(); writer.put(TEST_KEY, Lsn(0x10), Value::Image(TEST_IMG("foo at 0x10")))?; @@ -2196,7 +2196,7 @@ pub mod tests { let mut keyspace = KeySpaceAccum::new(); - let mut test_key = Key::from_hex("010000222233333333444444445500000000").unwrap(); + let mut test_key = Key::from_hex("012222222233333333444444445500000000").unwrap(); let mut blknum = 0; for _ in 0..50 { for _ in 0..1000 { @@ -2239,7 +2239,7 @@ pub mod tests { const NUM_KEYS: usize = 1000; - let mut test_key = Key::from_hex("010000222233333333444444445500000000").unwrap(); + let mut test_key = Key::from_hex("012222222233333333444444445500000000").unwrap(); let mut keyspace = KeySpaceAccum::new(); @@ -2313,7 +2313,7 @@ pub mod tests { const NUM_KEYS: usize = 1000; - let mut test_key = Key::from_hex("010000222233333333444444445500000000").unwrap(); + let mut test_key = Key::from_hex("012222222233333333444444445500000000").unwrap(); let mut keyspace = KeySpaceAccum::new(); diff --git a/pageserver/src/layered_repository/layer_map.rs b/pageserver/src/layered_repository/layer_map.rs index a224f0fe3c..b49492c2d3 100644 --- a/pageserver/src/layered_repository/layer_map.rs +++ b/pageserver/src/layered_repository/layer_map.rs @@ -16,9 +16,12 @@ use crate::layered_repository::InMemoryLayer; use crate::repository::Key; use anyhow::Result; use lazy_static::lazy_static; +use num_traits::identities::{One, Zero}; +use num_traits::{Bounded, Num, Signed}; use rstar::{RTree, RTreeObject, AABB}; use std::collections::VecDeque; use std::ops::Range; +use std::ops::{Add, Div, Mul, Neg, Rem, Sub}; use std::sync::Arc; use tracing::*; use zenith_metrics::{register_int_gauge, IntGauge}; @@ -54,7 +57,8 @@ pub struct LayerMap { /// All the historic layers are kept here historic_layers: RTree, - /// L0 layers has key range: (Key::MIN..Key::MAX) and locating them using R-Tree search is very inefficient + /// L0 layers has key range: (Key::MIN..Key::MAX) and locating them using R-Tree search is very inefficient. + /// So l) layers are also pushed in l0_layers vector. l0_layers: Vec>, } @@ -62,6 +66,100 @@ struct LayerEnvelope { layer: Arc, } +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Debug)] +struct IntKey(i128); + +impl Bounded for IntKey { + fn min_value() -> Self { + IntKey(i128::MIN) + } + fn max_value() -> Self { + IntKey(i128::MAX) + } +} + +impl Signed for IntKey { + fn is_positive(&self) -> bool { + self.0 > 0 + } + fn is_negative(&self) -> bool { + self.0 < 0 + } + fn signum(&self) -> Self { + IntKey(self.0.signum()) + } + fn abs(&self) -> Self { + IntKey(self.0.abs()) + } + fn abs_sub(&self, other: &Self) -> Self { + IntKey(self.0.abs_sub(&other.0)) + } +} + +impl Neg for IntKey { + type Output = Self; + fn neg(self) -> Self::Output { + IntKey(-self.0) + } +} + +impl Rem for IntKey { + type Output = Self; + fn rem(self, rhs: Self) -> Self::Output { + IntKey(self.0 % rhs.0) + } +} + +impl Div for IntKey { + type Output = Self; + fn div(self, rhs: Self) -> Self::Output { + IntKey(self.0 / rhs.0) + } +} + +impl Add for IntKey { + type Output = Self; + fn add(self, rhs: Self) -> Self::Output { + IntKey(self.0 + rhs.0) + } +} + +impl Sub for IntKey { + type Output = Self; + fn sub(self, rhs: Self) -> Self::Output { + IntKey(self.0 - rhs.0) + } +} + +impl Mul for IntKey { + type Output = Self; + fn mul(self, rhs: Self) -> Self::Output { + IntKey(self.0.wrapping_mul(rhs.0)) + } +} + +impl One for IntKey { + fn one() -> Self { + IntKey(1) + } +} + +impl Zero for IntKey { + fn zero() -> Self { + IntKey(0) + } + fn is_zero(&self) -> bool { + self.0 == 0 + } +} + +impl Num for IntKey { + type FromStrRadixErr = ::FromStrRadixErr; + fn from_str_radix(str: &str, radix: u32) -> Result { + Ok(IntKey(i128::from_str_radix(str, radix)?)) + } +} + impl PartialEq for LayerEnvelope { fn eq(&self, other: &Self) -> bool { // FIXME: ptr_eq might fail to return true for 'dyn' @@ -74,13 +172,19 @@ impl PartialEq for LayerEnvelope { } impl RTreeObject for LayerEnvelope { - type Envelope = AABB<[i128; 2]>; + type Envelope = AABB<[IntKey; 2]>; fn envelope(&self) -> Self::Envelope { let key_range = self.layer.get_key_range(); let lsn_range = self.layer.get_lsn_range(); AABB::from_corners( - [key_range.start.to_i128(), lsn_range.start.0 as i128], - [key_range.end.to_i128(), lsn_range.end.0 as i128 - 1], // end is exlusive + [ + IntKey(key_range.start.to_i128()), + IntKey(lsn_range.start.0 as i128), + ], + [ + IntKey(key_range.end.to_i128() - 1), + IntKey(lsn_range.end.0 as i128 - 1), + ], // end is exlusive ) } } @@ -109,8 +213,8 @@ impl LayerMap { let mut latest_img: Option> = None; let mut latest_img_lsn: Option = None; let envelope = AABB::from_corners( - [key.to_i128(), 0i128], - [key.to_i128(), end_lsn.0 as i128 - 1], + [IntKey(key.to_i128()), IntKey(0i128)], + [IntKey(key.to_i128()), IntKey(end_lsn.0 as i128 - 1)], ); for e in self .historic_layers @@ -255,8 +359,11 @@ impl LayerMap { loop { let mut made_progress = false; let envelope = AABB::from_corners( - [range_remain.start.to_i128(), lsn.0 as i128], - [range_remain.end.to_i128(), disk_consistent_lsn.0 as i128], + [IntKey(range_remain.start.to_i128()), IntKey(lsn.0 as i128)], + [ + IntKey(range_remain.end.to_i128() - 1), + IntKey(disk_consistent_lsn.0 as i128), + ], ); for e in self .historic_layers @@ -312,7 +419,10 @@ impl LayerMap { fn find_latest_image(&self, key: Key, lsn: Lsn) -> Option> { let mut candidate_lsn = Lsn(0); let mut candidate = None; - let envelope = AABB::from_corners([key.to_i128(), 0], [key.to_i128(), lsn.0 as i128]); + let envelope = AABB::from_corners( + [IntKey(key.to_i128()), IntKey(0)], + [IntKey(key.to_i128()), IntKey(lsn.0 as i128)], + ); for e in self .historic_layers .locate_in_envelope_intersecting(&envelope) @@ -353,8 +463,8 @@ impl LayerMap { points = vec![key_range.start]; let envelope = AABB::from_corners( - [key_range.start.to_i128(), 0], - [key_range.end.to_i128(), lsn.0 as i128], + [IntKey(key_range.start.to_i128()), IntKey(0)], + [IntKey(key_range.end.to_i128()), IntKey(lsn.0 as i128)], ); for e in self .historic_layers @@ -395,8 +505,14 @@ impl LayerMap { pub fn count_deltas(&self, key_range: &Range, lsn_range: &Range) -> Result { let mut result = 0; let envelope = AABB::from_corners( - [key_range.start.to_i128(), lsn_range.start.0 as i128], - [key_range.end.to_i128(), lsn_range.end.0 as i128 - 1], + [ + IntKey(key_range.start.to_i128()), + IntKey(lsn_range.start.0 as i128), + ], + [ + IntKey(key_range.end.to_i128() - 1), + IntKey(lsn_range.end.0 as i128 - 1), + ], ); for e in self .historic_layers @@ -406,13 +522,6 @@ impl LayerMap { if !l.is_incremental() { continue; } - if !range_overlaps(&l.get_lsn_range(), lsn_range) { - info!( - "l.lsn_range={:?}, lsn_range={:?}", - l.get_lsn_range(), - lsn_range - ); - } assert!(range_overlaps(&l.get_lsn_range(), lsn_range)); assert!(range_overlaps(&l.get_key_range(), key_range)); diff --git a/pageserver/src/repository.rs b/pageserver/src/repository.rs index c21751a39b..d38cf06916 100644 --- a/pageserver/src/repository.rs +++ b/pageserver/src/repository.rs @@ -33,12 +33,12 @@ impl Key { /// As far as Zenith is not supporting tablespace (because of lack of access to local file system), /// we can assume that only some predefined namespace OIDs are used which can fit in u16 pub fn to_i128(&self) -> i128 { - assert!(self.field2 < 0xFFFFF || self.field2 == !0u32); - (((self.field1 & 0x7f) as i128) << 120) - | ((self.field5 as i128) << 112) - | (((self.field2 & 0xFFFF) as i128) << 96) - | ((self.field3 as i128) << 64) - | ((self.field4 as i128) << 32) + assert!(self.field2 < 0xFFFFF || self.field2 == 0xFFFFFFFF || self.field2 == 0x22222222); + (((self.field1 & 0xf) as i128) << 120) + | (((self.field2 & 0xFFFF) as i128) << 104) + | ((self.field3 as i128) << 72) + | ((self.field4 as i128) << 40) + | ((self.field5 as i128) << 32) | self.field6 as i128 }