Insert into a leaf node by ID.
(&mut self, leaf_id: NodeId, key: K, value: V)
| 29 | |
| 30 | /// Insert into a leaf node by ID. |
| 31 | fn insert_into_leaf(&mut self, leaf_id: NodeId, key: K, value: V) -> InsertResult<K, V> { |
| 32 | let leaf = match self.get_leaf_mut(leaf_id) { |
| 33 | Some(leaf) => leaf, |
| 34 | None => return InsertResult::Updated(None), |
| 35 | }; |
| 36 | |
| 37 | // Do binary search once and use the result throughout |
| 38 | match leaf.binary_search_keys(&key) { |
| 39 | Ok(index) => { |
| 40 | // Key already exists, update the value |
| 41 | if let Some(old_val) = leaf.get_value_mut(index) { |
| 42 | let old_value = std::mem::replace(old_val, value); |
| 43 | InsertResult::Updated(Some(old_value)) |
| 44 | } else { |
| 45 | InsertResult::Updated(None) |
| 46 | } |
| 47 | } |
| 48 | Err(index) => { |
| 49 | // Key doesn't exist, need to insert |
| 50 | // Check if split is needed BEFORE inserting |
| 51 | if !leaf.is_full() { |
| 52 | // Room to insert without splitting |
| 53 | leaf.insert_at_index(index, key, value); |
| 54 | // Simple insertion - no split needed |
| 55 | return InsertResult::Updated(None); |
| 56 | } |
| 57 | |
| 58 | // Node is full, need to split |
| 59 | // Don't insert first. That causes the Vecs to overflow. |
| 60 | |
| 61 | // Calculate split point for better balance while ensuring both sides have at least min_keys |
| 62 | let min_keys = leaf.capacity / 2; // min_keys() inlined |
| 63 | let total_keys = leaf.keys.len(); |
| 64 | |
| 65 | // Use a more balanced split: aim for roughly equal distribution |
| 66 | let mid = total_keys.div_ceil(2); // Round up for odd numbers |
| 67 | |
| 68 | // Ensure the split point respects minimum requirements |
| 69 | let mid = mid.max(min_keys).min(total_keys - min_keys); |
| 70 | |
| 71 | // Split the keys and values |
| 72 | let right_keys = leaf.keys.split_off(mid); |
| 73 | let right_values = leaf.values.split_off(mid); |
| 74 | |
| 75 | // Store values we need before releasing the leaf borrow |
| 76 | let leaf_capacity = leaf.capacity; |
| 77 | let leaf_next = leaf.next; |
| 78 | let leaf_keys_len = leaf.keys.len(); |
| 79 | |
| 80 | // End the leaf borrow scope here |
| 81 | |
| 82 | // Create the new right node - allocate directly in arena to reuse deallocated nodes |
| 83 | let new_right_id = self.allocate_leaf_with_data( |
| 84 | leaf_capacity, |
| 85 | right_keys, |
| 86 | right_values, |
| 87 | leaf_next, // Right node takes over the next pointer |
| 88 | ); |
no test coverage detected