diff --git a/canbench_results.yml b/canbench_results.yml index 9ee52cc3..e108bb41 100644 --- a/canbench_results.yml +++ b/canbench_results.yml @@ -1,583 +1,583 @@ benches: btreemap_get_blob_128_1024: total: - instructions: 907603660 + instructions: 893670424 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_128_1024_v2: total: - instructions: 1007199087 + instructions: 995207241 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_16_1024: total: - instructions: 372167770 + instructions: 337648227 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_16_1024_v2: total: - instructions: 457662954 + instructions: 444217122 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_256_1024: total: - instructions: 1426064341 + instructions: 1415511747 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_256_1024_v2: total: - instructions: 1527035040 + instructions: 1514168820 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_32_1024: total: - instructions: 419061339 + instructions: 381907680 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_32_1024_v2: total: - instructions: 504369966 + instructions: 488487485 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_4_1024: total: - instructions: 252116091 + instructions: 227261128 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_4_1024_v2: total: - instructions: 335503348 + instructions: 325869733 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_512_1024: total: - instructions: 2460840276 + instructions: 2450115183 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_512_1024_v2: total: - instructions: 2563001074 + instructions: 2550121969 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_64_1024: total: - instructions: 668073317 + instructions: 628111428 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_64_1024_v2: total: - instructions: 753614013 + instructions: 741635543 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_8_1024: total: - instructions: 292704842 + instructions: 268581241 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_8_1024_v2: total: - instructions: 375374739 + instructions: 361655931 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_8_u64: total: - instructions: 257168736 + instructions: 225674655 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_blob_8_u64_v2: total: - instructions: 340837593 + instructions: 327541207 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_u64_blob_8: total: - instructions: 238330996 + instructions: 206115900 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_u64_blob_8_v2: total: - instructions: 297681217 + instructions: 284748710 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_u64_u64: total: - instructions: 241234542 + instructions: 209460964 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_get_u64_u64_v2: total: - instructions: 305672279 + instructions: 292825246 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_insert_10mib_values: total: - instructions: 145922325 + instructions: 143780576 heap_increase: 0 stable_memory_increase: 32 scopes: {} btreemap_insert_blob_1024_128: total: - instructions: 5161914701 + instructions: 5164808652 heap_increase: 0 stable_memory_increase: 262 scopes: {} btreemap_insert_blob_1024_128_v2: total: - instructions: 5551068081 + instructions: 5281950728 heap_increase: 0 stable_memory_increase: 196 scopes: {} btreemap_insert_blob_1024_16: total: - instructions: 5117369042 + instructions: 5121789897 heap_increase: 0 stable_memory_increase: 241 scopes: {} btreemap_insert_blob_1024_16_v2: total: - instructions: 5508502115 + instructions: 5240004829 heap_increase: 0 stable_memory_increase: 181 scopes: {} btreemap_insert_blob_1024_256: total: - instructions: 5184904755 + instructions: 5191598730 heap_increase: 0 stable_memory_increase: 292 scopes: {} btreemap_insert_blob_1024_256_v2: total: - instructions: 5574315002 + instructions: 5307930234 heap_increase: 0 stable_memory_increase: 219 scopes: {} btreemap_insert_blob_1024_32: total: - instructions: 5124609174 + instructions: 5130230816 heap_increase: 0 stable_memory_increase: 239 scopes: {} btreemap_insert_blob_1024_32_v2: total: - instructions: 5514811773 + instructions: 5250490862 heap_increase: 0 stable_memory_increase: 180 scopes: {} btreemap_insert_blob_1024_4: total: - instructions: 5013244404 + instructions: 5020410565 heap_increase: 0 stable_memory_increase: 235 scopes: {} btreemap_insert_blob_1024_4_v2: total: - instructions: 5408573739 + instructions: 5138630598 heap_increase: 0 stable_memory_increase: 176 scopes: {} btreemap_insert_blob_1024_512: total: - instructions: 5296495023 + instructions: 5313901374 heap_increase: 0 stable_memory_increase: 348 scopes: {} btreemap_insert_blob_1024_512_v2: total: - instructions: 5692610171 + instructions: 5431298131 heap_increase: 0 stable_memory_increase: 261 scopes: {} btreemap_insert_blob_1024_64: total: - instructions: 5160684248 + instructions: 5162795781 heap_increase: 0 stable_memory_increase: 250 scopes: {} btreemap_insert_blob_1024_64_v2: total: - instructions: 5550351966 + instructions: 5281814406 heap_increase: 0 stable_memory_increase: 188 scopes: {} btreemap_insert_blob_1024_8: total: - instructions: 5098598668 + instructions: 5104330157 heap_increase: 0 stable_memory_increase: 237 scopes: {} btreemap_insert_blob_1024_8_v2: total: - instructions: 5491459791 + instructions: 5221951548 heap_increase: 0 stable_memory_increase: 178 scopes: {} btreemap_insert_blob_128_1024: total: - instructions: 1521330782 + instructions: 1472048001 heap_increase: 0 stable_memory_increase: 260 scopes: {} btreemap_insert_blob_128_1024_v2: total: - instructions: 1651666210 + instructions: 1581626427 heap_increase: 0 stable_memory_increase: 195 scopes: {} btreemap_insert_blob_16_1024: total: - instructions: 914664896 + instructions: 851823832 heap_increase: 0 stable_memory_increase: 215 scopes: {} btreemap_insert_blob_16_1024_v2: total: - instructions: 1012902411 + instructions: 965540836 heap_increase: 0 stable_memory_increase: 161 scopes: {} btreemap_insert_blob_256_1024: total: - instructions: 2072292372 + instructions: 2043379400 heap_increase: 0 stable_memory_increase: 292 scopes: {} btreemap_insert_blob_256_1024_v2: total: - instructions: 2262462135 + instructions: 2156403366 heap_increase: 0 stable_memory_increase: 219 scopes: {} btreemap_insert_blob_32_1024: total: - instructions: 971198185 + instructions: 903787236 heap_increase: 0 stable_memory_increase: 230 scopes: {} btreemap_insert_blob_32_1024_v2: total: - instructions: 1063770231 + instructions: 1017622127 heap_increase: 0 stable_memory_increase: 173 scopes: {} btreemap_insert_blob_4_1024: total: - instructions: 702289156 + instructions: 645314996 heap_increase: 0 stable_memory_increase: 123 scopes: {} btreemap_insert_blob_4_1024_v2: total: - instructions: 787277534 + instructions: 747132204 heap_increase: 0 stable_memory_increase: 92 scopes: {} btreemap_insert_blob_512_1024: total: - instructions: 3204820188 + instructions: 3177514301 heap_increase: 0 stable_memory_increase: 351 scopes: {} btreemap_insert_blob_512_1024_v2: total: - instructions: 3464702305 + instructions: 3288704008 heap_increase: 0 stable_memory_increase: 263 scopes: {} btreemap_insert_blob_64_1024: total: - instructions: 1242018908 + instructions: 1170984032 heap_increase: 0 stable_memory_increase: 245 scopes: {} btreemap_insert_blob_64_1024_v2: total: - instructions: 1345198105 + instructions: 1292569627 heap_increase: 0 stable_memory_increase: 183 scopes: {} btreemap_insert_blob_8_1024: total: - instructions: 828112100 + instructions: 770542808 heap_increase: 0 stable_memory_increase: 183 scopes: {} btreemap_insert_blob_8_1024_v2: total: - instructions: 919898223 + instructions: 876068225 heap_increase: 0 stable_memory_increase: 138 scopes: {} btreemap_insert_blob_8_u64: total: - instructions: 424334575 + instructions: 368655501 heap_increase: 0 stable_memory_increase: 6 scopes: {} btreemap_insert_blob_8_u64_v2: total: - instructions: 524551164 + instructions: 483666450 heap_increase: 0 stable_memory_increase: 4 scopes: {} btreemap_insert_u64_blob_8: total: - instructions: 435858693 + instructions: 377443641 heap_increase: 0 stable_memory_increase: 7 scopes: {} btreemap_insert_u64_blob_8_v2: total: - instructions: 502390007 + instructions: 460731804 heap_increase: 0 stable_memory_increase: 5 scopes: {} btreemap_insert_u64_u64: total: - instructions: 448328834 + instructions: 390178100 heap_increase: 0 stable_memory_increase: 7 scopes: {} btreemap_insert_u64_u64_v2: total: - instructions: 518609796 + instructions: 476655765 heap_increase: 0 stable_memory_increase: 6 scopes: {} btreemap_iter_10mib_values: total: - instructions: 25583733 + instructions: 25429011 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_iter_count_10mib_values: total: - instructions: 544088 + instructions: 523576 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_iter_count_small_values: total: - instructions: 11007833 + instructions: 9978843 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_iter_rev_10mib_values: total: - instructions: 25584039 + instructions: 25428310 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_iter_rev_small_values: total: - instructions: 23800315 + instructions: 15984294 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_iter_small_values: total: - instructions: 23721014 + instructions: 15967493 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_keys_10mib_values: total: - instructions: 534290 + instructions: 513164 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_keys_rev_10mib_values: total: - instructions: 595467 + instructions: 515517 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_keys_rev_small_values: total: - instructions: 14369449 + instructions: 10350635 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_keys_small_values: total: - instructions: 11184261 + instructions: 10114798 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_128_1024: total: - instructions: 1916049094 + instructions: 1842207367 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_128_1024_v2: total: - instructions: 2060148972 + instructions: 2007214795 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_16_1024: total: - instructions: 1175020990 + instructions: 1069875544 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_16_1024_v2: total: - instructions: 1310763950 + instructions: 1227916080 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_256_1024: total: - instructions: 2563737681 + instructions: 2513310681 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_256_1024_v2: total: - instructions: 2715023284 + instructions: 2671355871 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_32_1024: total: - instructions: 1257978407 + instructions: 1149405495 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_32_1024_v2: total: - instructions: 1396032068 + instructions: 1312387688 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_4_1024: total: - instructions: 730553298 + instructions: 653919477 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_4_1024_v2: total: - instructions: 832333088 + instructions: 775125688 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_512_1024: total: - instructions: 3925489037 + instructions: 3913637896 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_512_1024_v2: total: - instructions: 4079819871 + instructions: 4074072942 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_64_1024: total: - instructions: 1579858589 + instructions: 1484708886 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_64_1024_v2: total: - instructions: 1719850337 + instructions: 1655573592 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_8_1024: total: - instructions: 958326169 + instructions: 863066043 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_8_1024_v2: total: - instructions: 1076065710 + instructions: 1003523478 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_8_u64: total: - instructions: 549471466 + instructions: 486533270 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_blob_8_u64_v2: total: - instructions: 685613050 + instructions: 644099809 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_u64_blob_8: total: - instructions: 609380674 + instructions: 541098489 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_u64_blob_8_v2: total: - instructions: 705692037 + instructions: 659949359 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_u64_u64: total: - instructions: 634570938 + instructions: 562530659 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_remove_u64_u64_v2: total: - instructions: 739939423 + instructions: 691055139 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_values_10mib_values: total: - instructions: 17277830 + instructions: 17139887 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_values_rev_10mib_values: total: - instructions: 17276742 + instructions: 17138678 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_values_rev_small_values: total: - instructions: 22619653 + instructions: 15685594 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_values_small_values: total: - instructions: 22560352 + instructions: 15644789 heap_increase: 0 stable_memory_increase: 0 scopes: {} diff --git a/src/btreemap/node.rs b/src/btreemap/node.rs index 50f3cbd2..4df66600 100644 --- a/src/btreemap/node.rs +++ b/src/btreemap/node.rs @@ -49,10 +49,11 @@ pub type Entry = (K, Vec); #[derive(Debug)] pub struct Node { address: Address, - keys: Vec, + // 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. - encoded_values: RefCell>, + // INVARIANT: the list is sorted by key. + keys_and_encoded_values: Vec<(K, RefCell)>, // 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
, @@ -106,9 +107,13 @@ impl Node { pub fn get_max(&self, memory: &M) -> Entry { match self.node_type { NodeType::Leaf => { - let last_idx = self.encoded_values.borrow().len() - 1; + let last_idx = self.keys_and_encoded_values.len() - 1; ( - self.keys.last().expect("A node can never be empty").clone(), + self.keys_and_encoded_values + .last() + .expect("A node can never be empty") + .0 + .clone(), self.value(last_idx, memory).to_vec(), ) } @@ -147,34 +152,62 @@ impl Node { /// Returns true if the node cannot store anymore entries, false otherwise. pub fn is_full(&self) -> bool { - self.keys.len() >= CAPACITY + self.keys_and_encoded_values.len() >= CAPACITY } /// Swaps the entry at index `idx` with the given entry, returning the old entry. pub fn swap_entry( &mut self, idx: usize, - (mut key, value): Entry, + (key, value): Entry, memory: &M, ) -> Entry { - core::mem::swap(&mut self.keys[idx], &mut key); - let old_value = self.value(idx, memory).to_vec(); - self.encoded_values.borrow_mut()[idx] = Value::ByVal(value); - (key, old_value) + let (old_key, old_value) = core::mem::replace( + &mut self.keys_and_encoded_values[idx], + (key, RefCell::new(Value::ByVal(value))), + ); + ( + old_key, + self.resolve_value(RefCell::into_inner(old_value), memory), + ) } /// Returns a copy of the entry at the specified index. pub fn entry(&self, idx: usize, memory: &M) -> Entry { - (self.keys[idx].clone(), self.value(idx, memory).to_vec()) + ( + self.keys_and_encoded_values[idx].0.clone(), + self.value(idx, memory).to_vec(), + ) } /// Returns a reference to the encoded value at the specified index. pub fn value(&self, idx: usize, memory: &M) -> Ref<[u8]> { // Load and cache the value from the underlying memory if needed. - { - let mut values = self.encoded_values.borrow_mut(); + 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)); + } + + // 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.") + } + }) + } - if let Value::ByRef(offset) = values[idx] { + 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, @@ -184,22 +217,13 @@ impl Node { }; let value_len = read_u32(&reader, Address::from(offset.get())) as usize; - let mut value = vec![0; value_len]; - reader.read((offset + U32_SIZE).get(), &mut value); + let mut bytes = vec![0; value_len]; + reader.read((offset + U32_SIZE).get(), &mut bytes); - // Cache the value internally. - values[idx] = Value::ByVal(value); + bytes } + Value::ByVal(bytes) => bytes, } - - // Return a reference to the value. - Ref::map(self.encoded_values.borrow(), |values| { - if let Value::ByVal(v) = &values[idx] { - &v[..] - } else { - unreachable!("value must have been loaded already."); - } - }) } fn page_size(&self) -> PageSize { @@ -208,7 +232,7 @@ impl Node { /// Returns a reference to the key at the specified index. pub fn key(&self, idx: usize) -> &K { - &self.keys[idx] + &self.keys_and_encoded_values[idx].0 } /// Returns the child's address at the given index. @@ -243,25 +267,20 @@ impl Node { /// Inserts a new entry at the specified index. pub fn insert_entry(&mut self, idx: usize, (key, encoded_value): Entry) { - self.keys.insert(idx, key); - self.encoded_values - .borrow_mut() - .insert(idx, Value::ByVal(encoded_value)); + self.keys_and_encoded_values + .insert(idx, (key, RefCell::new(Value::ByVal(encoded_value)))); } /// Removes the entry at the specified index. pub fn remove_entry(&mut self, idx: usize, memory: &M) -> Entry { - let value = self.value(idx, memory).to_vec(); - self.encoded_values.borrow_mut().remove(idx); - (self.keys.remove(idx), value) + let (key, value) = self.keys_and_encoded_values.remove(idx); + (key, self.resolve_value(RefCell::into_inner(value), memory)) } /// Adds a new entry at the back of the node. pub fn push_entry(&mut self, (key, encoded_value): Entry) { - self.keys.push(key); - self.encoded_values - .borrow_mut() - .push(Value::ByVal(encoded_value)); + self.keys_and_encoded_values + .push((key, RefCell::new(Value::ByVal(encoded_value)))); } /// Removes an entry from the back of the node. @@ -271,14 +290,15 @@ impl Node { return None; } - let key = self.keys.pop().expect("node must not be empty"); - let last_value = self.value(len - 1, memory).to_vec(); - self.encoded_values - .borrow_mut() + let (key, last_value) = self + .keys_and_encoded_values .pop() .expect("node must not be empty"); - Some((key, last_value)) + Some(( + key, + self.resolve_value(RefCell::into_inner(last_value), memory), + )) } /// Merges the entries and children of the `source` node into self, along with the median entry. @@ -313,8 +333,7 @@ impl Node { Self::append(&mut source, self, median); // Move the entries and children into self. - self.keys = core::mem::take(&mut source.keys); - self.encoded_values = core::mem::take(&mut source.encoded_values); + self.keys_and_encoded_values = core::mem::take(&mut source.keys_and_encoded_values); self.children = core::mem::take(&mut source.children); } @@ -343,32 +362,32 @@ impl Node { a.push_entry(median); - a.keys.append(&mut b.keys); - a.encoded_values - .borrow_mut() - .append(&mut b.encoded_values.borrow_mut()); + a.keys_and_encoded_values + .append(&mut b.keys_and_encoded_values); // Move the children (if any exist). a.children.append(&mut b.children); // Assert postconditions. - assert_eq!(b.keys.len(), 0); - assert_eq!(b.encoded_values.borrow().len(), 0); + assert_eq!(b.keys_and_encoded_values.len(), 0); assert_eq!(b.children.len(), 0); } #[cfg(test)] pub fn entries(&self, memory: &M) -> Vec> { - self.keys + self.keys_and_encoded_values .iter() - .cloned() - .zip((0..self.keys.len()).map(|idx| self.value(idx, memory).to_vec())) + .enumerate() + .map(|(idx, (key, _))| (key.clone(), self.value(idx, memory).to_vec())) .collect() } #[cfg(test)] - pub fn keys(&self) -> &[K] { - &self.keys + pub fn keys(&self) -> Vec { + self.keys_and_encoded_values + .iter() + .map(|(key, _)| key.clone()) + .collect() } #[cfg(test)] @@ -378,7 +397,7 @@ impl Node { /// Returns the number of entries in the node. pub fn entries_len(&self) -> usize { - self.keys.len() + self.keys_and_encoded_values.len() } /// Searches for the key in the node's entries. @@ -388,7 +407,8 @@ impl Node { /// returned, containing the index where a matching key could be inserted /// while maintaining sorted order. pub fn search(&self, key: &K) -> Result { - self.keys.binary_search(key) + self.keys_and_encoded_values + .binary_search_by_key(&key, |entry| &entry.0) } /// Returns the maximum size a node can be if it has bounded keys and values. @@ -400,7 +420,7 @@ impl Node { /// Returns true if the node is at the minimum required size, false otherwise. pub fn at_minimum(&self) -> bool { - self.keys.len() < B + self.keys_and_encoded_values.len() < B } /// Returns true if an entry can be removed without having to merge it into another node @@ -419,8 +439,7 @@ impl Node { } // Move the entries and children above the median into the new sibling. - sibling.keys = self.keys.split_off(B); - *sibling.encoded_values.borrow_mut() = self.encoded_values.borrow_mut().split_off(B); + sibling.keys_and_encoded_values = self.keys_and_encoded_values.split_off(B); if self.node_type == NodeType::Internal { sibling.children = self.children.split_off(B); } diff --git a/src/btreemap/node/tests.rs b/src/btreemap/node/tests.rs index 54552480..11aee289 100644 --- a/src/btreemap/node/tests.rs +++ b/src/btreemap/node/tests.rs @@ -293,3 +293,19 @@ fn overflows_end_with_null_after_nodes_growing_and_shrinking() { NULL.get() ); } + +#[test] +fn can_call_node_value_multiple_times_on_same_index() { + let mem = make_memory(); + let allocator_addr = Address::from(0); + let page_size = PageSize::Value(500); + let mut allocator = Allocator::new(mem.clone(), allocator_addr, page_size.get().into()); + + let node_addr = allocator.allocate(); + let mut node = Node::new_v2(node_addr, NodeType::Leaf, page_size); + node.push_entry((1u32, vec![1, 2, 3])); + + let value1 = node.value(0, &mem); + let value2 = node.value(0, &mem); + assert_eq!(&value1[..], &value2[..]); +} diff --git a/src/btreemap/node/v1.rs b/src/btreemap/node/v1.rs index 6854e72e..f65b3d28 100644 --- a/src/btreemap/node/v1.rs +++ b/src/btreemap/node/v1.rs @@ -44,8 +44,7 @@ impl Node { Node { address, node_type, - keys: vec![], - encoded_values: RefCell::default(), + keys_and_encoded_values: vec![], children: vec![], version: Version::V1(page_size), overflows: Vec::with_capacity(0), @@ -64,8 +63,7 @@ impl Node { let _p = canbench::profile("node_load_v1"); // Load the entries. - let mut keys = Vec::with_capacity(header.num_entries as usize); - let mut encoded_values = Vec::with_capacity(header.num_entries as usize); + let mut keys_encoded_values = Vec::with_capacity(header.num_entries as usize); let mut offset = NodeHeader::size(); let mut buf = Vec::with_capacity(max_key_size.max(max_value_size) as usize); for _ in 0..header.num_entries { @@ -78,10 +76,9 @@ impl Node { memory.read((address + offset).get(), &mut buf); offset += Bytes::from(max_key_size); let key = K::from_bytes(Cow::Borrowed(&buf)); - keys.push(key); - // Values are loaded lazily. Store a reference and skip loading it. - encoded_values.push(Value::ByRef(offset)); + keys_encoded_values.push((key, RefCell::new(Value::ByRef(offset)))); + offset += U32_SIZE + Bytes::from(max_value_size); } @@ -89,19 +86,19 @@ impl Node { let mut children = vec![]; if header.node_type == INTERNAL_NODE_TYPE { // The number of children is equal to the number of entries + 1. + children.reserve(header.num_entries as usize + 1); for _ in 0..header.num_entries + 1 { let child = Address::from(read_u64(memory, address + offset)); offset += Address::size(); children.push(child); } - assert_eq!(children.len(), keys.len() + 1); + assert_eq!(children.len(), keys_encoded_values.len() + 1); } Self { address, - keys, - encoded_values: RefCell::new(encoded_values), + keys_and_encoded_values: keys_encoded_values, children, node_type: match header.node_type { LEAF_NODE_TYPE => NodeType::Leaf, @@ -125,15 +122,18 @@ impl Node { assert!(self.children.is_empty()); } NodeType::Internal => { - assert_eq!(self.children.len(), self.keys.len() + 1); + assert_eq!(self.children.len(), self.keys_and_encoded_values.len() + 1); } }; // We should never be saving an empty node. - assert!(!self.keys.is_empty() || !self.children.is_empty()); + assert!(!self.keys_and_encoded_values.is_empty() || !self.children.is_empty()); // Assert entries are sorted in strictly increasing order. - assert!(self.keys.windows(2).all(|e| e[0] < e[1])); + assert!(self + .keys_and_encoded_values + .windows(2) + .all(|e| e[0].0 < e[1].0)); let (max_key_size, max_value_size) = match self.version { Version::V1(DerivedPageSize { @@ -150,7 +150,7 @@ impl Node { NodeType::Leaf => LEAF_NODE_TYPE, NodeType::Internal => INTERNAL_NODE_TYPE, }, - num_entries: self.keys.len() as u16, + num_entries: self.keys_and_encoded_values.len() as u16, }; write_struct(&header, self.address, memory); @@ -159,12 +159,12 @@ impl Node { // Load all the values. This is necessary so that we don't overwrite referenced // values when writing the entries to the node. - for i in 0..self.keys.len() { + for i in 0..self.keys_and_encoded_values.len() { self.value(i, memory); } // Write the entries. - for (idx, key) in self.keys.iter().enumerate() { + for (idx, (key, _)) in self.keys_and_encoded_values.iter().enumerate() { // Write the size of the key. let key_bytes = key.to_bytes_checked(); write_u32(memory, self.address + offset, key_bytes.len() as u32); diff --git a/src/btreemap/node/v2.rs b/src/btreemap/node/v2.rs index 6d9cde7d..3a2c8cd4 100644 --- a/src/btreemap/node/v2.rs +++ b/src/btreemap/node/v2.rs @@ -98,8 +98,7 @@ impl Node { address, node_type, version: Version::V2(page_size), - keys: vec![], - encoded_values: RefCell::default(), + keys_and_encoded_values: vec![], children: vec![], overflows: Vec::with_capacity(0), } @@ -150,8 +149,7 @@ impl Node { } // Load the keys. - let mut keys = Vec::with_capacity(num_entries); - let mut encoded_values = Vec::with_capacity(num_entries); + let mut keys_encoded_values = Vec::with_capacity(num_entries); let mut buf = vec![]; for _ in 0..num_entries { // Load the key's size. @@ -170,21 +168,20 @@ impl Node { reader.read(offset.get(), &mut buf); let key = K::from_bytes(Cow::Borrowed(&buf)); offset += Bytes::from(key_size); - keys.push(key); + keys_encoded_values.push((key, RefCell::new(Value::ByRef(Bytes::from(0usize))))); } // Load the values - for _ in 0..num_entries { + for (_key, value) in keys_encoded_values.iter_mut() { // Load the values lazily. - encoded_values.push(Value::ByRef(Bytes::from(offset.get()))); + *value = RefCell::new(Value::ByRef(Bytes::from(offset.get()))); let value_size = read_u32(&reader, offset) as usize; offset += U32_SIZE + Bytes::from(value_size as u64); } Self { address, - keys, - encoded_values: RefCell::new(encoded_values), + keys_and_encoded_values: keys_encoded_values, children, node_type, version: Version::V2(page_size), @@ -199,11 +196,10 @@ impl Node { let page_size = self.version.page_size().get(); assert!(page_size >= MINIMUM_PAGE_SIZE); - assert_eq!(self.keys.len(), self.encoded_values.borrow().len()); // Load all the values. This is necessary so that we don't overwrite referenced // values when writing the entries to the node. - for i in 0..self.keys.len() { + for i in 0..self.keys_and_encoded_values.len() { self.value(i, allocator.memory()); } @@ -225,7 +221,7 @@ impl Node { NodeType::Leaf => LEAF_NODE_TYPE, NodeType::Internal => INTERNAL_NODE_TYPE, }, - num_entries: self.keys.len() as u16, + num_entries: self.keys_and_encoded_values.len() as u16, }; writer.write_struct(&header, offset); @@ -243,7 +239,7 @@ impl Node { } // Write the keys. - for key in self.keys.iter() { + for (key, _) in self.keys_and_encoded_values.iter() { let key_bytes = key.to_bytes_checked(); // Write the size of the key if it isn't fixed in size.