diff --git a/canbench_results.yml b/canbench_results.yml index bd1995fe..cd34e136 100644 --- a/canbench_results.yml +++ b/canbench_results.yml @@ -1,595 +1,595 @@ benches: btreemap_get_blob_128_1024: total: - instructions: 893670424 + instructions: 879302205 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_128_1024_v2: total: - instructions: 995207241 + instructions: 986234201 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_16_1024: total: - instructions: 337648227 + instructions: 315520793 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_16_1024_v2: total: - instructions: 444217122 + instructions: 424439334 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_256_1024: total: - instructions: 1415511747 + instructions: 1410478508 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_256_1024_v2: total: - instructions: 1514168820 + instructions: 1515420842 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_32_1024: total: - instructions: 381907680 + instructions: 359080553 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_32_1024_v2: total: - instructions: 488487485 + instructions: 467643018 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_4_1024: total: - instructions: 227261128 + instructions: 205936205 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_4_1024_v2: total: - instructions: 325869733 + instructions: 304383660 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_512_1024: total: - instructions: 2450115183 + instructions: 2465612866 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_512_1024_v2: total: - instructions: 2550121969 + instructions: 2571792093 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_64_1024: total: - instructions: 628111428 + instructions: 611173672 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_64_1024_v2: total: - instructions: 741635543 + instructions: 727594763 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_8_1024: total: - instructions: 268581241 + instructions: 242798942 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_8_1024_v2: total: - instructions: 361655931 + instructions: 337855918 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_8_u64: total: - instructions: 225674655 + instructions: 215475284 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_8_u64_v2: total: - instructions: 327541207 + instructions: 326446044 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_u64_blob_8: total: - instructions: 206115900 + instructions: 198160835 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_u64_blob_8_v2: total: - instructions: 284748710 + instructions: 285194478 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_u64_u64: total: - instructions: 209460964 + instructions: 199393722 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_u64_u64_v2: total: - instructions: 292825246 + instructions: 291906450 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_insert_10mib_values: total: - instructions: 143780576 + instructions: 143394599 heap_increase: 0 stable_memory_increase: 32 scopes: {} btreemap_insert_blob_1024_128: total: - instructions: 5164808652 + instructions: 5103816812 heap_increase: 0 stable_memory_increase: 262 scopes: {} btreemap_insert_blob_1024_128_v2: total: - instructions: 5281950728 + instructions: 5223665926 heap_increase: 0 stable_memory_increase: 196 scopes: {} btreemap_insert_blob_1024_16: total: - instructions: 5121789897 + instructions: 5060658098 heap_increase: 0 stable_memory_increase: 241 scopes: {} btreemap_insert_blob_1024_16_v2: total: - instructions: 5240004829 + instructions: 5181580835 heap_increase: 0 stable_memory_increase: 181 scopes: {} btreemap_insert_blob_1024_256: total: - instructions: 5191598730 + instructions: 5130558722 heap_increase: 0 stable_memory_increase: 292 scopes: {} btreemap_insert_blob_1024_256_v2: total: - instructions: 5307930234 + instructions: 5249596386 heap_increase: 0 stable_memory_increase: 219 scopes: {} btreemap_insert_blob_1024_32: total: - instructions: 5130230816 + instructions: 5069315515 heap_increase: 0 stable_memory_increase: 239 scopes: {} btreemap_insert_blob_1024_32_v2: total: - instructions: 5250490862 + instructions: 5192319151 heap_increase: 0 stable_memory_increase: 180 scopes: {} btreemap_insert_blob_1024_4: total: - instructions: 5020410565 + instructions: 4959470000 heap_increase: 0 stable_memory_increase: 235 scopes: {} btreemap_insert_blob_1024_4_v2: total: - instructions: 5138630598 + instructions: 5080388188 heap_increase: 0 stable_memory_increase: 176 scopes: {} btreemap_insert_blob_1024_512: total: - instructions: 5313901374 + instructions: 5252901073 heap_increase: 0 stable_memory_increase: 348 scopes: {} btreemap_insert_blob_1024_512_v2: total: - instructions: 5431298131 + instructions: 5373023593 heap_increase: 0 stable_memory_increase: 261 scopes: {} btreemap_insert_blob_1024_64: total: - instructions: 5162795781 + instructions: 5101699743 heap_increase: 0 stable_memory_increase: 250 scopes: {} btreemap_insert_blob_1024_64_v2: total: - instructions: 5281814406 + instructions: 5223434507 heap_increase: 0 stable_memory_increase: 188 scopes: {} btreemap_insert_blob_1024_8: total: - instructions: 5104330157 + instructions: 5043314359 heap_increase: 0 stable_memory_increase: 237 scopes: {} btreemap_insert_blob_1024_8_v2: total: - instructions: 5221951548 + instructions: 5163637162 heap_increase: 0 stable_memory_increase: 178 scopes: {} btreemap_insert_blob_128_1024: total: - instructions: 1472048001 + instructions: 1458078497 heap_increase: 0 stable_memory_increase: 260 scopes: {} btreemap_insert_blob_128_1024_v2: total: - instructions: 1581626427 + instructions: 1570349058 heap_increase: 0 stable_memory_increase: 195 scopes: {} btreemap_insert_blob_16_1024: total: - instructions: 851823832 + instructions: 839064490 heap_increase: 0 stable_memory_increase: 215 scopes: {} btreemap_insert_blob_16_1024_v2: total: - instructions: 965540836 + instructions: 955395829 heap_increase: 0 stable_memory_increase: 161 scopes: {} btreemap_insert_blob_256_1024: total: - instructions: 2043379400 + instructions: 2028664457 heap_increase: 0 stable_memory_increase: 292 scopes: {} btreemap_insert_blob_256_1024_v2: total: - instructions: 2156403366 + instructions: 2144398075 heap_increase: 0 stable_memory_increase: 219 scopes: {} btreemap_insert_blob_32_1024: total: - instructions: 903787236 + instructions: 890749049 heap_increase: 0 stable_memory_increase: 230 scopes: {} btreemap_insert_blob_32_1024_v2: total: - instructions: 1017622127 + instructions: 1007248566 heap_increase: 0 stable_memory_increase: 173 scopes: {} btreemap_insert_blob_4_1024: total: - instructions: 645314996 + instructions: 633932227 heap_increase: 0 stable_memory_increase: 123 scopes: {} btreemap_insert_blob_4_1024_v2: total: - instructions: 747132204 + instructions: 738087270 heap_increase: 0 stable_memory_increase: 92 scopes: {} btreemap_insert_blob_512_1024: total: - instructions: 3177514301 + instructions: 3161385472 heap_increase: 0 stable_memory_increase: 351 scopes: {} btreemap_insert_blob_512_1024_v2: total: - instructions: 3288704008 + instructions: 3275260995 heap_increase: 0 stable_memory_increase: 263 scopes: {} btreemap_insert_blob_64_1024: total: - instructions: 1170984032 + instructions: 1157359426 heap_increase: 0 stable_memory_increase: 245 scopes: {} btreemap_insert_blob_64_1024_v2: total: - instructions: 1292569627 + instructions: 1281618754 heap_increase: 0 stable_memory_increase: 183 scopes: {} btreemap_insert_blob_8_1024: total: - instructions: 770542808 + instructions: 758180070 heap_increase: 0 stable_memory_increase: 183 scopes: {} btreemap_insert_blob_8_1024_v2: total: - instructions: 876068225 + instructions: 866287942 heap_increase: 0 stable_memory_increase: 138 scopes: {} btreemap_insert_blob_8_u64: total: - instructions: 368655501 + instructions: 353807315 heap_increase: 0 stable_memory_increase: 6 scopes: {} btreemap_insert_blob_8_u64_v2: total: - instructions: 483666450 + instructions: 473686702 heap_increase: 0 stable_memory_increase: 4 scopes: {} btreemap_insert_u64_blob_8: total: - instructions: 377443641 + instructions: 364631146 heap_increase: 0 stable_memory_increase: 7 scopes: {} btreemap_insert_u64_blob_8_v2: total: - instructions: 460731804 + instructions: 450222711 heap_increase: 0 stable_memory_increase: 5 scopes: {} btreemap_insert_u64_u64: total: - instructions: 390178100 + instructions: 374696730 heap_increase: 0 stable_memory_increase: 7 scopes: {} btreemap_insert_u64_u64_v2: total: - instructions: 476655765 + instructions: 462904999 heap_increase: 0 stable_memory_increase: 6 scopes: {} btreemap_iter_10mib_values: total: - instructions: 25429011 + instructions: 17116720 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_iter_count_10mib_values: total: - instructions: 523576 + instructions: 527176 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_iter_count_small_values: total: - instructions: 9978843 + instructions: 10158843 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_iter_rev_10mib_values: total: - instructions: 25428310 + instructions: 17114625 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_iter_rev_small_values: total: - instructions: 15984294 + instructions: 14524294 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_iter_small_values: total: - instructions: 15967493 + instructions: 14527493 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_keys_10mib_values: total: - instructions: 513164 + instructions: 516764 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_keys_rev_10mib_values: total: - instructions: 515517 + instructions: 519117 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_keys_rev_small_values: total: - instructions: 10350635 + instructions: 10530635 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_keys_small_values: total: - instructions: 10114798 + instructions: 10294798 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_read_every_third_value_from_range: total: - instructions: 160211242 + instructions: 113084618 heap_increase: 0 stable_memory_increase: 0 - scopes: { } + scopes: {} btreemap_read_keys_from_range: total: - instructions: 160211242 + instructions: 113084618 heap_increase: 0 stable_memory_increase: 0 - scopes: { } + scopes: {} btreemap_remove_blob_128_1024: total: - instructions: 1842207367 + instructions: 1814329611 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_128_1024_v2: total: - instructions: 2007214795 + instructions: 1982178501 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_16_1024: total: - instructions: 1069875544 + instructions: 1046555128 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_16_1024_v2: total: - instructions: 1227916080 + instructions: 1207409244 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_256_1024: total: - instructions: 2513310681 + instructions: 2484528504 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_256_1024_v2: total: - instructions: 2671355871 + instructions: 2645421668 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_32_1024: total: - instructions: 1149405495 + instructions: 1125110448 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_32_1024_v2: total: - instructions: 1312387688 + instructions: 1290917923 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_4_1024: total: - instructions: 653919477 + instructions: 639953529 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_4_1024_v2: total: - instructions: 775125688 + instructions: 763706218 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_512_1024: total: - instructions: 3913637896 + instructions: 3880456183 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_512_1024_v2: total: - instructions: 4074072942 + instructions: 4043734433 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_64_1024: total: - instructions: 1484708886 + instructions: 1458217613 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_64_1024_v2: total: - instructions: 1655573592 + instructions: 1631937179 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_8_1024: total: - instructions: 863066043 + instructions: 843328385 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_8_1024_v2: total: - instructions: 1003523478 + instructions: 986540048 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_8_u64: total: - instructions: 486533270 + instructions: 465951671 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_8_u64_v2: total: - instructions: 644099809 + instructions: 626297968 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_u64_blob_8: total: - instructions: 541098489 + instructions: 516865037 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_u64_blob_8_v2: total: - instructions: 659949359 + instructions: 637827582 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_u64_u64: total: - instructions: 562530659 + instructions: 537895420 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_u64_u64_v2: total: - instructions: 691055139 + instructions: 668544917 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_values_10mib_values: total: - instructions: 17139887 + instructions: 17140501 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_values_rev_10mib_values: total: - instructions: 17138678 + instructions: 17139292 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_values_rev_small_values: total: - instructions: 15685594 + instructions: 15756258 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_values_small_values: total: - instructions: 15644789 + instructions: 15715453 heap_increase: 0 stable_memory_increase: 0 scopes: {} diff --git a/src/btreemap.rs b/src/btreemap.rs index c1c76025..b06a7f65 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -353,7 +353,7 @@ where /// key.to_bytes().len() <= max_size(Key) /// value.to_bytes().len() <= max_size(Value) pub fn insert(&mut self, key: K, value: V) -> Option { - let value = value.to_bytes_checked().to_vec(); + let value = value.to_bytes_checked().into_owned(); let root = if self.root_addr == NULL { // No root present. Allocate one. @@ -523,7 +523,7 @@ where fn get_helper(&self, node_addr: Address, key: &K) -> Option> { let node = self.load_node(node_addr); match node.search(key) { - Ok(idx) => Some(node.value(idx, self.memory()).to_vec()), + Ok(idx) => Some(node.into_entry(idx, self.memory()).1), Err(idx) => { match node.node_type() { NodeType::Leaf => None, // Key not found. diff --git a/src/btreemap/iter.rs b/src/btreemap/iter.rs index 5c683585..82869508 100644 --- a/src/btreemap/iter.rs +++ b/src/btreemap/iter.rs @@ -455,7 +455,7 @@ where fn next(&mut self) -> Option { self.0.next_map(|node, entry_idx| { let (key, encoded_value) = node.entry(entry_idx, self.0.map.memory()); - (key, V::from_bytes(Cow::Owned(encoded_value))) + (key.clone(), V::from_bytes(Cow::Borrowed(encoded_value))) }) } @@ -476,7 +476,7 @@ where fn next_back(&mut self) -> Option { self.0.next_back_map(|node, entry_idx| { let (key, encoded_value) = node.entry(entry_idx, self.0.map.memory()); - (key, V::from_bytes(Cow::Owned(encoded_value))) + (key.clone(), V::from_bytes(Cow::Borrowed(encoded_value))) }) } } @@ -537,7 +537,7 @@ where fn next(&mut self) -> Option { self.0.next_map(|node, entry_idx| { let encoded_value = node.value(entry_idx, self.0.map.memory()); - V::from_bytes(Cow::Borrowed(&encoded_value)) + V::from_bytes(Cow::Borrowed(encoded_value)) }) } @@ -558,7 +558,7 @@ where fn next_back(&mut self) -> Option { self.0.next_back_map(|node, entry_idx| { let encoded_value = node.value(entry_idx, self.0.map.memory()); - V::from_bytes(Cow::Borrowed(&encoded_value)) + V::from_bytes(Cow::Borrowed(encoded_value)) }) } } diff --git a/src/btreemap/node.rs b/src/btreemap/node.rs index 4df66600..ff70ccef 100644 --- a/src/btreemap/node.rs +++ b/src/btreemap/node.rs @@ -6,7 +6,7 @@ use crate::{ write, write_struct, write_u32, Memory, }; use std::borrow::{Borrow, Cow}; -use std::cell::{Ref, RefCell}; +use std::cell::OnceCell; mod io; #[cfg(test)] @@ -37,6 +37,7 @@ pub enum NodeType { } pub type Entry = (K, Vec); +pub type EntryRef<'a, K> = (&'a K, &'a [u8]); /// A node of a B-Tree. /// @@ -50,10 +51,8 @@ pub type Entry = (K, Vec); pub struct Node { address: Address, // List of tuples consisting of a key and the encoded value. - // Values are stored in a Refcell as they are loaded lazily. - // A RefCell allows loading the value and caching it without requiring exterior mutability. // INVARIANT: the list is sorted by key. - keys_and_encoded_values: Vec<(K, RefCell)>, + keys_and_encoded_values: Vec<(K, Value)>, // For the key at position I, children[I] points to the left // child of this key and children[I + 1] points to the right child. children: Vec
, @@ -136,7 +135,8 @@ impl Node { match self.node_type { NodeType::Leaf => { // NOTE: a node can never be empty, so this access is safe. - self.entry(0, memory) + let entry = self.entry(0, memory); + (entry.0.clone(), entry.1.to_vec()) } NodeType::Internal => { let first_child = Self::load( @@ -164,66 +164,46 @@ impl Node { ) -> Entry { let (old_key, old_value) = core::mem::replace( &mut self.keys_and_encoded_values[idx], - (key, RefCell::new(Value::ByVal(value))), + (key, Value::by_value(value)), ); - ( - old_key, - self.resolve_value(RefCell::into_inner(old_value), memory), - ) + (old_key, self.extract_value(old_value, memory)) } - /// Returns a copy of the entry at the specified index. - pub fn entry(&self, idx: usize, memory: &M) -> Entry { + /// Returns a reference to the entry at the specified index. + pub fn entry(&self, idx: usize, memory: &M) -> EntryRef { ( - self.keys_and_encoded_values[idx].0.clone(), - self.value(idx, memory).to_vec(), + &self.keys_and_encoded_values[idx].0, + self.value(idx, memory), ) } /// Returns a reference to the encoded value at the specified index. - pub fn value(&self, idx: usize, memory: &M) -> Ref<[u8]> { + pub fn value(&self, idx: usize, memory: &M) -> &[u8] { // Load and cache the value from the underlying memory if needed. - let encoded_value = &self.keys_and_encoded_values[idx].1; - - // We borrow the value immutably first. We only borrow the value mutably if it hasn't been - // cached yet. This is to ensure that no references have been given out to the cached value - // when we call .borrow_mut(). - let encoded_value_borrow = encoded_value.borrow(); - if let Value::ByRef(offset) = *encoded_value_borrow { - // We drop the borrow explicitly because we want to borrow mutably on the next line. - drop(encoded_value_borrow); - *encoded_value.borrow_mut() = - Value::ByVal(self.resolve_value(Value::ByRef(offset), memory)); - } + self.keys_and_encoded_values[idx] + .1 + .get_or_load(|offset| self.load_value_from_memory(offset, memory)) + } - // Return a reference to the value. - Ref::map(encoded_value.borrow(), |value| match value { - Value::ByVal(v) => &v[..], - Value::ByRef(_) => { - unreachable!("value must have been loaded already in the code above.") - } - }) + /// Extracts the contents of value (by loading it first if it's not loaded yet). + fn extract_value(&self, value: Value, memory: &M) -> Vec { + value.take_or_load(|offset| self.load_value_from_memory(offset, memory)) } - fn resolve_value(&self, value: Value, memory: &M) -> Vec { - match value { - Value::ByRef(offset) => { - // Value isn't loaded yet. - let reader = NodeReader { - address: self.address, - overflows: &self.overflows, - page_size: self.page_size(), - memory, - }; + /// Loads a value from stable memory at the given offset. + fn load_value_from_memory(&self, offset: Bytes, memory: &M) -> Vec { + let reader = NodeReader { + address: self.address, + overflows: &self.overflows, + page_size: self.page_size(), + memory, + }; - let value_len = read_u32(&reader, Address::from(offset.get())) as usize; - let mut bytes = vec![0; value_len]; - reader.read((offset + U32_SIZE).get(), &mut bytes); + let value_len = read_u32(&reader, Address::from(offset.get())) as usize; + let mut bytes = vec![0; value_len]; + reader.read((offset + U32_SIZE).get(), &mut bytes); - bytes - } - Value::ByVal(bytes) => bytes, - } + bytes } fn page_size(&self) -> PageSize { @@ -268,19 +248,26 @@ impl Node { /// Inserts a new entry at the specified index. pub fn insert_entry(&mut self, idx: usize, (key, encoded_value): Entry) { self.keys_and_encoded_values - .insert(idx, (key, RefCell::new(Value::ByVal(encoded_value)))); + .insert(idx, (key, Value::by_value(encoded_value))); + } + + /// Returns the entry at the specified index while consuming this node. + pub fn into_entry(mut self, idx: usize, memory: &M) -> Entry { + let keys_and_encoded_values = core::mem::take(&mut self.keys_and_encoded_values); + let (key, value) = keys_and_encoded_values.into_iter().nth(idx).unwrap(); + (key, self.extract_value(value, memory)) } /// Removes the entry at the specified index. pub fn remove_entry(&mut self, idx: usize, memory: &M) -> Entry { let (key, value) = self.keys_and_encoded_values.remove(idx); - (key, self.resolve_value(RefCell::into_inner(value), memory)) + (key, self.extract_value(value, memory)) } /// Adds a new entry at the back of the node. pub fn push_entry(&mut self, (key, encoded_value): Entry) { self.keys_and_encoded_values - .push((key, RefCell::new(Value::ByVal(encoded_value)))); + .push((key, Value::by_value(encoded_value))); } /// Removes an entry from the back of the node. @@ -295,10 +282,7 @@ impl Node { .pop() .expect("node must not be empty"); - Some(( - key, - self.resolve_value(RefCell::into_inner(last_value), memory), - )) + Some((key, self.extract_value(last_value, memory))) } /// Merges the entries and children of the `source` node into self, along with the median entry. @@ -474,14 +458,55 @@ impl NodeHeader { } } -// The value in a K/V pair. +/// The value in a K/V pair. #[derive(Debug)] enum Value { - // The value's encoded bytes. + /// The value's encoded bytes. ByVal(Vec), - // The value's offset in the node. - ByRef(Bytes), + ByRef { + /// The value's offset in the node. + offset: Bytes, + /// The lazily loaded encoded bytes. + loaded_value: OnceCell>, + }, +} + +impl Value { + pub fn by_ref(offset: Bytes) -> Self { + Self::ByRef { + offset, + loaded_value: Default::default(), + } + } + + pub fn by_value(value: Vec) -> Self { + Self::ByVal(value) + } + + /// Returns a reference to the value if the value has been loaded or runs the given function to + /// load the value. + pub fn get_or_load(&self, load: impl FnOnce(Bytes) -> Vec) -> &[u8] { + match self { + Value::ByVal(v) => &v[..], + Value::ByRef { + offset, + loaded_value: value, + } => value.get_or_init(|| load(*offset)), + } + } + + /// Extracts the value while consuming self if the value has been loaded or runs the given + /// function to load the value. + pub fn take_or_load(self, load: impl FnOnce(Bytes) -> Vec) -> Vec { + match self { + Value::ByVal(v) => v, + Value::ByRef { + offset, + loaded_value: value, + } => value.into_inner().unwrap_or_else(|| load(offset)), + } + } } /// Stores version-specific data. diff --git a/src/btreemap/node/tests.rs b/src/btreemap/node/tests.rs index 11aee289..ff1158ca 100644 --- a/src/btreemap/node/tests.rs +++ b/src/btreemap/node/tests.rs @@ -307,5 +307,5 @@ fn can_call_node_value_multiple_times_on_same_index() { let value1 = node.value(0, &mem); let value2 = node.value(0, &mem); - assert_eq!(&value1[..], &value2[..]); + assert_eq!(value1, value2); } diff --git a/src/btreemap/node/v1.rs b/src/btreemap/node/v1.rs index f65b3d28..9bb5b411 100644 --- a/src/btreemap/node/v1.rs +++ b/src/btreemap/node/v1.rs @@ -77,7 +77,7 @@ impl Node { offset += Bytes::from(max_key_size); let key = K::from_bytes(Cow::Borrowed(&buf)); // Values are loaded lazily. Store a reference and skip loading it. - keys_encoded_values.push((key, RefCell::new(Value::ByRef(offset)))); + keys_encoded_values.push((key, Value::by_ref(offset))); offset += U32_SIZE + Bytes::from(max_value_size); } @@ -180,7 +180,7 @@ impl Node { offset += U32_SIZE; // Write the value. - write(memory, (self.address + offset).get(), &value); + write(memory, (self.address + offset).get(), value); offset += Bytes::from(max_value_size); } diff --git a/src/btreemap/node/v2.rs b/src/btreemap/node/v2.rs index 3a2c8cd4..5f8699ab 100644 --- a/src/btreemap/node/v2.rs +++ b/src/btreemap/node/v2.rs @@ -168,13 +168,13 @@ impl Node { reader.read(offset.get(), &mut buf); let key = K::from_bytes(Cow::Borrowed(&buf)); offset += Bytes::from(key_size); - keys_encoded_values.push((key, RefCell::new(Value::ByRef(Bytes::from(0usize))))); + keys_encoded_values.push((key, Value::by_ref(Bytes::from(0usize)))); } // Load the values for (_key, value) in keys_encoded_values.iter_mut() { // Load the values lazily. - *value = RefCell::new(Value::ByRef(Bytes::from(offset.get()))); + *value = Value::by_ref(Bytes::from(offset.get())); let value_size = read_u32(&reader, offset) as usize; offset += U32_SIZE + Bytes::from(value_size as u64); } @@ -261,7 +261,7 @@ impl Node { offset += U32_SIZE; // Write the value. - writer.write(offset, &value); + writer.write(offset, value); offset += Bytes::from(value.len()); }