diff --git a/benchmarks/btreemap/canbench_results.yml b/benchmarks/btreemap/canbench_results.yml index 1d2e9d80..ca6d517d 100644 --- a/benchmarks/btreemap/canbench_results.yml +++ b/benchmarks/btreemap/canbench_results.yml @@ -51,21 +51,21 @@ benches: btreemap_v2_contains_then_remove_blob_32_128: total: calls: 1 - instructions: 929822486 + instructions: 916748064 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_contains_then_remove_u64_u64: total: calls: 1 - instructions: 736289775 + instructions: 724683402 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_contains_then_remove_u64_u64_nocache: total: calls: 1 - instructions: 783052278 + instructions: 771336352 heap_increase: 0 stable_memory_increase: 0 scopes: {} @@ -366,21 +366,21 @@ benches: btreemap_v2_get_then_remove_blob_32_128: total: calls: 1 - instructions: 962059972 + instructions: 948048002 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_get_then_remove_u64_u64: total: calls: 1 - instructions: 740840122 + instructions: 729255732 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_get_then_remove_u64_u64_nocache: total: calls: 1 - instructions: 787584834 + instructions: 775868908 heap_increase: 0 stable_memory_increase: 0 scopes: {} @@ -1052,35 +1052,35 @@ benches: btreemap_v2_mem_manager_remove_blob512_u64: total: calls: 1 - instructions: 4264053662 + instructions: 4213350182 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_mem_manager_remove_u64_blob512: total: calls: 1 - instructions: 879965338 + instructions: 865364327 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_mem_manager_remove_u64_u64: total: calls: 1 - instructions: 735887467 + instructions: 721090250 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_mem_manager_remove_u64_vec512: total: calls: 1 - instructions: 1219427655 + instructions: 1199286269 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_mem_manager_remove_vec512_u64: total: calls: 1 - instructions: 3039345496 + instructions: 3017281991 heap_increase: 0 stable_memory_increase: 0 scopes: {} @@ -1318,322 +1318,322 @@ benches: btreemap_v2_remove_100k_u64_u64: total: calls: 1 - instructions: 6934239178 + instructions: 6780980586 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_100k_u64_u64_nocache: total: calls: 1 - instructions: 6919819278 + instructions: 6766560686 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_10mib_values: total: calls: 1 - instructions: 4711743233 + instructions: 4711742998 heap_increase: 0 stable_memory_increase: 657 scopes: {} btreemap_v2_remove_blob8_u64: total: calls: 1 - instructions: 585416459 + instructions: 573170816 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_blob_1024_128: total: calls: 1 - instructions: 7280230548 + instructions: 7196863329 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_blob_128_128: total: calls: 1 - instructions: 1578192013 + instructions: 1557479337 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_blob_16_128: total: calls: 1 - instructions: 665039226 + instructions: 650345726 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_blob_256_128: total: calls: 1 - instructions: 2400178691 + instructions: 2370892126 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_blob_32_0: total: calls: 1 - instructions: 654578268 + instructions: 640152243 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_blob_32_1024: total: calls: 1 - instructions: 981436308 + instructions: 968549810 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_blob_32_128: total: calls: 1 - instructions: 745566132 + instructions: 732417422 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_blob_32_16: total: calls: 1 - instructions: 699604173 + instructions: 686386610 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_blob_32_256: total: calls: 1 - instructions: 782321020 + instructions: 769665683 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_blob_32_32: total: calls: 1 - instructions: 711451431 + instructions: 697927666 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_blob_32_4: total: calls: 1 - instructions: 696115676 + instructions: 682388965 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_blob_32_512: total: calls: 1 - instructions: 855760433 + instructions: 842408902 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_blob_32_64: total: calls: 1 - instructions: 736358929 + instructions: 722868205 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_blob_32_8: total: calls: 1 - instructions: 695620819 + instructions: 682294984 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_blob_4_128: total: calls: 1 - instructions: 453341383 + instructions: 444706706 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_blob_512_128: total: calls: 1 - instructions: 4029563559 + instructions: 3983580451 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_blob_64_128: total: calls: 1 - instructions: 906421907 + instructions: 894709754 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_blob_8_128: total: calls: 1 - instructions: 599811841 + instructions: 586957313 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_principal: total: calls: 1 - instructions: 682445857 + instructions: 668107276 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_u64_blob8: total: calls: 1 - instructions: 567554311 + instructions: 555937388 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_u64_u64: total: calls: 1 - instructions: 588118977 + instructions: 576403051 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_u64_vec8: total: calls: 1 - instructions: 572766786 + instructions: 561219824 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_vec8_u64: total: calls: 1 - instructions: 754547542 + instructions: 736204600 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_vec_1024_128: total: calls: 1 - instructions: 4389758335 + instructions: 4337756124 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_vec_128_128: total: calls: 1 - instructions: 1405073079 + instructions: 1390380396 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_vec_16_128: total: calls: 1 - instructions: 917676522 + instructions: 897239497 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_vec_256_128: total: calls: 1 - instructions: 2219301691 + instructions: 2202607496 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_vec_32_0: total: calls: 1 - instructions: 831967364 + instructions: 821887879 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_vec_32_1024: total: calls: 1 - instructions: 1689269104 + instructions: 1672368990 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_vec_32_128: total: calls: 1 - instructions: 1032868785 + instructions: 1020766859 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_vec_32_16: total: calls: 1 - instructions: 867682921 + instructions: 857345002 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_vec_32_256: total: calls: 1 - instructions: 1233221626 + instructions: 1220292800 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_vec_32_32: total: calls: 1 - instructions: 864129124 + instructions: 853868912 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_vec_32_4: total: calls: 1 - instructions: 858831537 + instructions: 848705558 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_vec_32_512: total: calls: 1 - instructions: 1397968704 + instructions: 1383857300 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_vec_32_64: total: calls: 1 - instructions: 963345905 + instructions: 952364259 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_vec_32_8: total: calls: 1 - instructions: 853023147 + instructions: 843110679 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_vec_4_128: total: calls: 1 - instructions: 660778727 + instructions: 646547915 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_vec_512_128: total: calls: 1 - instructions: 3036674847 + instructions: 3015691929 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_vec_64_128: total: calls: 1 - instructions: 1175810683 + instructions: 1163813147 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_vec_8_128: total: calls: 1 - instructions: 819786629 + instructions: 801757663 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreemap_v2_remove_zipf_10k_u64_u64: total: calls: 1 - instructions: 341014143 + instructions: 337292334 heap_increase: 0 stable_memory_increase: 0 scopes: {} diff --git a/benchmarks/btreeset/canbench_results.yml b/benchmarks/btreeset/canbench_results.yml index 7031b5e1..5149ce8d 100644 --- a/benchmarks/btreeset/canbench_results.yml +++ b/benchmarks/btreeset/canbench_results.yml @@ -492,70 +492,70 @@ benches: btreeset_remove_blob_1024: total: calls: 1 - instructions: 7723769472 + instructions: 7723668257 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreeset_remove_blob_128: total: calls: 1 - instructions: 1667435780 + instructions: 1667334565 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreeset_remove_blob_16: total: calls: 1 - instructions: 706481770 + instructions: 706383039 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreeset_remove_blob_256: total: calls: 1 - instructions: 2535147032 + instructions: 2535045817 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreeset_remove_blob_32: total: calls: 1 - instructions: 803118519 + instructions: 803013972 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreeset_remove_blob_512: total: calls: 1 - instructions: 4262483247 + instructions: 4262382032 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreeset_remove_blob_64: total: calls: 1 - instructions: 988152388 + instructions: 988047841 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreeset_remove_blob_8: total: calls: 1 - instructions: 684602545 + instructions: 684500484 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreeset_remove_u32: total: calls: 1 - instructions: 529154304 + instructions: 529052639 heap_increase: 0 stable_memory_increase: 0 scopes: {} btreeset_remove_u64: total: calls: 1 - instructions: 554060009 + instructions: 553978344 heap_increase: 0 stable_memory_increase: 0 scopes: {} diff --git a/src/btreemap.rs b/src/btreemap.rs index 80b42906..d768bbb4 100644 --- a/src/btreemap.rs +++ b/src/btreemap.rs @@ -1152,19 +1152,12 @@ where // An entry can't be removed from the child without merging. // See if it has a sibling where an entry can be removed without merging. - let mut left_sibling = if idx > 0 { - Some(self.load_node(node.child(idx - 1))) - } else { - None - }; + // Siblings are loaded lazily: if the left sibling can donate, we + // never need to load the right sibling (saves one node load). - let mut right_sibling = if idx + 1 < node.children_len() { - Some(self.load_node(node.child(idx + 1))) - } else { - None - }; + if idx > 0 { + let mut left_sibling = self.load_node(node.child(idx - 1)); - if let Some(ref mut left_sibling) = left_sibling { if left_sibling.can_remove_entry_without_merging() { // Case 3.a (left): // A key can be removed from the left child without merging. @@ -1212,73 +1205,76 @@ where assert_eq!(child.node_type(), NodeType::Leaf); } - self.save_node(left_sibling); + self.save_node(&mut left_sibling); self.save_node(&mut child); self.save_node(&mut node); return self.remove_helper(child, key); } - } - - if let Some(right_sibling) = &mut right_sibling { - if right_sibling.can_remove_entry_without_merging() { - // Case 3.a (right): - // A key can be removed from the right child without merging. - // - // [c] (parent) - // / \ - // (child) [a, b] [d, e, f] (right sibling) - // / - // [d'] - // - // In this case, we move a key down from the parent into the child - // and move a key from the right sibling up into the parent - // resulting in the following tree: - // - // [d] (parent) - // / \ - // (child) [a, b, c] [e, f] (right sibling) - // \ - // [d'] - // - // We then recurse to delete the key from the child. - // Remove the first entry from the right sibling. - let (right_sibling_key, right_sibling_value) = - right_sibling.remove_entry(0, self.memory()); - - // Replace the parent's entry with the one from the right sibling. - let parent_entry = node.swap_entry( - idx, - (right_sibling_key, right_sibling_value), - self.memory(), - ); - - // Move the entry from the parent into the child. - child.push_entry(parent_entry); - - // Move the first child of right_sibling into `child`. - match right_sibling.node_type() { - NodeType::Internal => { - assert_eq!(child.node_type(), NodeType::Internal); - child.push_child(right_sibling.remove_child(0)); - } - NodeType::Leaf => { - assert_eq!(child.node_type(), NodeType::Leaf); + // Left sibling is at minimum. Load right sibling to try + // rotation or decide which merge to perform. + if idx + 1 < node.children_len() { + let mut right_sibling = self.load_node(node.child(idx + 1)); + + if right_sibling.can_remove_entry_without_merging() { + // Case 3.a (right): + // A key can be removed from the right child without merging. + // + // [c] (parent) + // / \ + // (child) [a, b] [d, e, f] (right sibling) + // / + // [d'] + // + // In this case, we move a key down from the parent into the child + // and move a key from the right sibling up into the parent + // resulting in the following tree: + // + // [d] (parent) + // / \ + // (child) [a, b, c] [e, f] (right sibling) + // \ + // [d'] + // + // We then recurse to delete the key from the child. + + // Remove the first entry from the right sibling. + let (right_sibling_key, right_sibling_value) = + right_sibling.remove_entry(0, self.memory()); + + // Replace the parent's entry with the one from the right sibling. + let parent_entry = node.swap_entry( + idx, + (right_sibling_key, right_sibling_value), + self.memory(), + ); + + // Move the entry from the parent into the child. + child.push_entry(parent_entry); + + // Move the first child of right_sibling into `child`. + match right_sibling.node_type() { + NodeType::Internal => { + assert_eq!(child.node_type(), NodeType::Internal); + child.push_child(right_sibling.remove_child(0)); + } + NodeType::Leaf => { + assert_eq!(child.node_type(), NodeType::Leaf); + } } + + self.save_node(&mut right_sibling); + self.save_node(&mut child); + self.save_node(&mut node); + return self.remove_helper(child, key); } - self.save_node(right_sibling); - self.save_node(&mut child); - self.save_node(&mut node); - return self.remove_helper(child, key); + // Case 3.b: both siblings at minimum — prefer merging + // into the left sibling. + drop(right_sibling); } - } - - // Case 3.b: Both the left and right siblings are at their minimum sizes. - - if let Some(left_sibling) = left_sibling { - // Merge child into left sibling if it exists. + // Case 3.b (left): Merge child into left sibling. assert!(left_sibling.at_minimum()); let left_sibling = self.merge( child, @@ -1304,36 +1300,60 @@ where return self.remove_helper(left_sibling, key); } - if let Some(right_sibling) = right_sibling { - // Merge child into right sibling. + // No left sibling (idx == 0). The right sibling must exist. + let mut right_sibling = self.load_node(node.child(idx + 1)); - assert!(right_sibling.at_minimum()); - let right_sibling = self.merge( - child, - right_sibling, - node.remove_entry(idx, self.memory()), - ); + if right_sibling.can_remove_entry_without_merging() { + // Case 3.a (right), no left sibling variant. - // Removing child from parent. - node.remove_child(idx); + let (right_sibling_key, right_sibling_value) = + right_sibling.remove_entry(0, self.memory()); - if node.entries_len() == 0 { - let node_address = node.address(); - self.deallocate_node(node); + let parent_entry = node.swap_entry( + idx, + (right_sibling_key, right_sibling_value), + self.memory(), + ); - if node_address == self.root_addr { - // Update the root. - self.root_addr = right_sibling.address(); - self.save_header(); + child.push_entry(parent_entry); + + match right_sibling.node_type() { + NodeType::Internal => { + assert_eq!(child.node_type(), NodeType::Internal); + child.push_child(right_sibling.remove_child(0)); + } + NodeType::Leaf => { + assert_eq!(child.node_type(), NodeType::Leaf); } - } else { - self.save_node(&mut node); } - return self.remove_helper(right_sibling, key); + self.save_node(&mut right_sibling); + self.save_node(&mut child); + self.save_node(&mut node); + return self.remove_helper(child, key); + } + + // Case 3.b (right): Merge child into right sibling. + assert!(right_sibling.at_minimum()); + let right_sibling = + self.merge(child, right_sibling, node.remove_entry(idx, self.memory())); + + node.remove_child(idx); + + if node.entries_len() == 0 { + let node_address = node.address(); + self.deallocate_node(node); + + if node_address == self.root_addr { + // Update the root. + self.root_addr = right_sibling.address(); + self.save_header(); + } + } else { + self.save_node(&mut node); } - unreachable!("At least one of the siblings must exist."); + self.remove_helper(right_sibling, key) } } }