From 1ce4976e3675c35eaaf74b7e2b55510599a42d98 Mon Sep 17 00:00:00 2001 From: Patrick Insinger Date: Tue, 2 Nov 2021 12:47:59 -0700 Subject: [PATCH] pageserver - track size of VecMaps --- .../src/layered_repository/inmemory_layer.rs | 25 +++++++---- .../src/layered_repository/page_versions.rs | 4 +- zenith_utils/src/vec_map.rs | 45 ++++++++++++++----- 3 files changed, 53 insertions(+), 21 deletions(-) diff --git a/pageserver/src/layered_repository/inmemory_layer.rs b/pageserver/src/layered_repository/inmemory_layer.rs index 1722f2ad60..65ff522f8d 100644 --- a/pageserver/src/layered_repository/inmemory_layer.rs +++ b/pageserver/src/layered_repository/inmemory_layer.rs @@ -386,7 +386,8 @@ impl InMemoryLayer { PageVersion::Wal(rec) => rec.rec.len(), }; - let old = inner.page_versions.append_or_update_last(blknum, lsn, pv); + let (old, delta_size) = inner.page_versions.append_or_update_last(blknum, lsn, pv); + mem_usage += delta_size; if old.is_some() { // We already had an entry for this LSN. That's odd.. @@ -396,8 +397,7 @@ impl InMemoryLayer { ); } - inner.mem_usage += mem_usage; - GLOBAL_OPEN_MEM_USAGE.fetch_add(mem_usage, Ordering::Relaxed); + let mut delta_logical_size = 0; // Also update the relation size, if this extended the relation. if self.seg.rel.is_blocky() { @@ -431,9 +431,10 @@ impl InMemoryLayer { gapblknum, blknum ); - let old = inner + let (old, delta_size) = inner .page_versions .append_or_update_last(gapblknum, lsn, zeropv); + mem_usage += delta_size; // We already had an entry for this LSN. That's odd.. if old.is_some() { @@ -444,12 +445,18 @@ impl InMemoryLayer { } } - inner.segsizes.append_or_update_last(lsn, newsize).unwrap(); - return newsize - oldsize; + let (_old, delta_size) = + inner.segsizes.append_or_update_last(lsn, newsize).unwrap(); + mem_usage += delta_size; + + delta_logical_size = newsize - oldsize; } } - 0 + inner.mem_usage += mem_usage; + GLOBAL_OPEN_MEM_USAGE.fetch_add(mem_usage, Ordering::Relaxed); + + delta_logical_size } /// Remember that the relation was truncated at given LSN @@ -466,7 +473,9 @@ impl InMemoryLayer { let oldsize = inner.get_seg_size(lsn); assert!(segsize < oldsize); - let old = inner.segsizes.append_or_update_last(lsn, segsize).unwrap(); + let (old, delta_size) = inner.segsizes.append_or_update_last(lsn, segsize).unwrap(); + inner.mem_usage += delta_size; + GLOBAL_OPEN_MEM_USAGE.fetch_add(delta_size, Ordering::Relaxed); if old.is_some() { // We already had an entry for this LSN. That's odd.. diff --git a/pageserver/src/layered_repository/page_versions.rs b/pageserver/src/layered_repository/page_versions.rs index 5a7741dac4..4f27b59981 100644 --- a/pageserver/src/layered_repository/page_versions.rs +++ b/pageserver/src/layered_repository/page_versions.rs @@ -15,7 +15,7 @@ impl PageVersions { blknum: u32, lsn: Lsn, page_version: PageVersion, - ) -> Option { + ) -> (Option, usize) { let map = self.0.entry(blknum).or_insert_with(VecMap::default); map.append_or_update_last(lsn, page_version).unwrap() } @@ -119,7 +119,7 @@ mod tests { for blknum in 0..BLOCKS { for lsn in 0..LSNS { - let old = page_versions.append_or_update_last( + let (old, _delta_size) = page_versions.append_or_update_last( blknum, Lsn(lsn), empty_page_version.clone(), diff --git a/zenith_utils/src/vec_map.rs b/zenith_utils/src/vec_map.rs index 4e2c827b47..558721c724 100644 --- a/zenith_utils/src/vec_map.rs +++ b/zenith_utils/src/vec_map.rs @@ -1,4 +1,4 @@ -use std::{cmp::Ordering, ops::RangeBounds}; +use std::{alloc::Layout, cmp::Ordering, ops::RangeBounds}; use serde::{Deserialize, Serialize}; @@ -57,34 +57,39 @@ impl VecMap { /// Add a key value pair to the map. /// If `key` is less than or equal to the current maximum key /// the pair will not be added and InvalidKey error will be returned. - pub fn append(&mut self, key: K, value: V) -> Result<(), InvalidKey> { + pub fn append(&mut self, key: K, value: V) -> Result { if let Some((last_key, _last_value)) = self.0.last() { if &key <= last_key { return Err(InvalidKey); } } - self.0.push((key, value)); - Ok(()) + let delta_size = self.instrument_vec_op(|vec| vec.push((key, value))); + Ok(delta_size) } /// Update the maximum key value pair or add a new key value pair to the map. /// If `key` is less than the current maximum key no updates or additions /// will occur and InvalidKey error will be returned. - pub fn append_or_update_last(&mut self, key: K, mut value: V) -> Result, InvalidKey> { + pub fn append_or_update_last( + &mut self, + key: K, + mut value: V, + ) -> Result<(Option, usize), InvalidKey> { if let Some((last_key, last_value)) = self.0.last_mut() { match key.cmp(last_key) { Ordering::Less => return Err(InvalidKey), Ordering::Equal => { std::mem::swap(last_value, &mut value); - return Ok(Some(value)); + const DELTA_SIZE: usize = 0; + return Ok((Some(value), DELTA_SIZE)); } Ordering::Greater => {} } } - self.0.push((key, value)); - Ok(None) + let delta_size = self.instrument_vec_op(|vec| vec.push((key, value))); + Ok((None, delta_size)) } /// Split the map into two. @@ -110,7 +115,7 @@ impl VecMap { /// Move items from `other` to the end of `self`, leaving `other` empty. /// If any keys in `other` is less than or equal to any key in `self`, /// `InvalidKey` error will be returned and no mutation will occur. - pub fn extend(&mut self, other: &mut Self) -> Result<(), InvalidKey> { + pub fn extend(&mut self, other: &mut Self) -> Result { let self_last_opt = self.0.last().map(extract_key); let other_first_opt = other.0.last().map(extract_key); @@ -120,9 +125,27 @@ impl VecMap { } } - self.0.append(&mut other.0); + let delta_size = self.instrument_vec_op(|vec| vec.append(&mut other.0)); + Ok(delta_size) + } - Ok(()) + /// Instrument an operation on the underlying [`Vec`]. + /// Will panic if the operation decreases capacity. + /// Returns the increase in memory usage caused by the op. + fn instrument_vec_op(&mut self, op: impl FnOnce(&mut Vec<(K, V)>)) -> usize { + let old_cap = self.0.capacity(); + op(&mut self.0); + let new_cap = self.0.capacity(); + + match old_cap.cmp(&new_cap) { + Ordering::Less => { + let old_size = Layout::array::<(K, V)>(old_cap).unwrap().size(); + let new_size = Layout::array::<(K, V)>(new_cap).unwrap().size(); + new_size - old_size + } + Ordering::Equal => 0, + Ordering::Greater => panic!("VecMap capacity shouldn't ever decrease"), + } } }