Skip to content

Commit b638a93

Browse files
KentBeckona-agent
andcommitted
Update CompressedLeafNode to match LeafNode behavior with InsertResult and splitting
- Change insert() return type from Result<Option<V>, &str> to InsertResult<K, V> - Implement complete node splitting functionality: - split_and_insert() for handling capacity overflow - split() method for balanced node division - insert_at_index() helper for internal insertions - to_leaf_node() conversion for SplitNodeData compatibility - Update all tests to expect InsertResult variants: - InsertResult::Updated(None) for new insertions - InsertResult::Updated(Some(old_value)) for key updates - InsertResult::Split{...} for node splits - Maintain API consistency with regular LeafNode while preserving compressed storage - All 20 tests pass, including split scenarios and edge cases Co-authored-by: Ona <no-reply@ona.com>
1 parent 6878ff8 commit b638a93

File tree

1 file changed

+190
-23
lines changed

1 file changed

+190
-23
lines changed

rust/src/compressed_node.rs

Lines changed: 190 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
66
use std::marker::PhantomData;
77
use std::mem;
8-
use crate::types::NodeId;
8+
use crate::types::{NodeId, InsertResult, SplitNodeData};
99

1010
/// A leaf node compressed to exactly 4 cache lines (256 bytes) for optimal cache performance.
1111
///
@@ -181,20 +181,20 @@ where
181181
V: Copy,
182182
{
183183
/// Insert a key-value pair into the leaf.
184-
/// Returns Ok(Some(old_value)) if key existed, Ok(None) if new key, Err if full.
185-
pub fn insert(&mut self, key: K, value: V) -> Result<Option<V>, &'static str> {
184+
/// Returns InsertResult indicating success, update, or split needed.
185+
pub fn insert(&mut self, key: K, value: V) -> InsertResult<K, V> {
186186
let (index, found) = self.find_key_index(&key);
187187

188188
if found {
189189
// Key exists - update value and return old value
190190
let old_value = unsafe { *self.value_at(index) };
191191
unsafe { self.set_value_at(index, value) };
192-
return Ok(Some(old_value));
192+
return InsertResult::Updated(Some(old_value));
193193
}
194194

195-
// Key doesn't exist - check capacity
195+
// Key doesn't exist - check if we need to split
196196
if self.len >= self.capacity {
197-
return Err("Leaf is at capacity");
197+
return self.split_and_insert(key, value, index);
198198
}
199199

200200
// Insert new key at the found position
@@ -225,7 +225,115 @@ where
225225
// Increment length
226226
self.len += 1;
227227

228-
Ok(None) // New key inserted
228+
InsertResult::Updated(None) // New key inserted
229+
}
230+
231+
/// Split the node and insert the new key-value pair.
232+
fn split_and_insert(&mut self, key: K, value: V, insert_index: usize) -> InsertResult<K, V> {
233+
// First, insert the new key-value pair to create an overfull node
234+
self.insert_at_index(insert_index, key, value);
235+
236+
// Now split the overfull node
237+
let new_right = self.split();
238+
239+
// Determine the separator key (first key of right node)
240+
let separator_key = unsafe { *new_right.key_at(0) };
241+
242+
// Convert to regular LeafNode for SplitNodeData
243+
let new_right_leaf = new_right.to_leaf_node();
244+
245+
InsertResult::Split {
246+
old_value: None,
247+
new_node_data: SplitNodeData::Leaf(new_right_leaf),
248+
separator_key,
249+
}
250+
}
251+
252+
/// Insert a key-value pair at the specified index without capacity checks.
253+
fn insert_at_index(&mut self, index: usize, key: K, value: V) {
254+
let current_len = self.len as usize;
255+
256+
// Shift keys and values to make room
257+
if index < current_len {
258+
unsafe {
259+
// Shift keys right
260+
let keys_src = self.keys_ptr().add(index);
261+
let keys_dst = self.keys_ptr_mut().add(index + 1);
262+
std::ptr::copy(keys_src, keys_dst, current_len - index);
263+
264+
// Shift values right
265+
let values_src = self.values_ptr().add(index);
266+
let values_dst = self.values_ptr_mut().add(index + 1);
267+
std::ptr::copy(values_src, values_dst, current_len - index);
268+
}
269+
}
270+
271+
// Insert new key-value pair
272+
unsafe {
273+
self.set_key_at(index, key);
274+
self.set_value_at(index, value);
275+
}
276+
277+
// Increment length
278+
self.len += 1;
279+
}
280+
281+
/// Split this leaf node, returning the new right node.
282+
pub fn split(&mut self) -> CompressedLeafNode<K, V> {
283+
let total_keys = self.len as usize;
284+
285+
// Calculate split point for better balance
286+
let mid = total_keys.div_ceil(2); // Round up for odd numbers
287+
288+
// Create new right node with same capacity
289+
let mut new_right = CompressedLeafNode::new(self.capacity);
290+
291+
// Calculate how many keys go to the right node
292+
let right_count = total_keys - mid;
293+
new_right.len = right_count as u16;
294+
295+
// Copy keys and values to the right node
296+
unsafe {
297+
// Copy keys
298+
std::ptr::copy_nonoverlapping(
299+
self.keys_ptr().add(mid),
300+
new_right.keys_ptr_mut(),
301+
right_count,
302+
);
303+
304+
// Copy values
305+
std::ptr::copy_nonoverlapping(
306+
self.values_ptr().add(mid),
307+
new_right.values_ptr_mut(),
308+
right_count,
309+
);
310+
}
311+
312+
// Update this node's length
313+
self.len = mid as u16;
314+
315+
new_right
316+
}
317+
318+
/// Convert this CompressedLeafNode to a regular LeafNode.
319+
pub fn to_leaf_node(&self) -> crate::types::LeafNode<K, V> {
320+
let mut keys = Vec::with_capacity(self.len as usize);
321+
let mut values = Vec::with_capacity(self.len as usize);
322+
323+
// Copy all keys and values
324+
for i in 0..self.len as usize {
325+
unsafe {
326+
keys.push(*self.key_at(i));
327+
values.push(*self.value_at(i));
328+
}
329+
}
330+
331+
crate::types::LeafNode {
332+
capacity: self.capacity as usize,
333+
keys,
334+
values,
335+
next: crate::types::NULL_NODE,
336+
}
229337
}
230338

231339
/// Get a value by key.
@@ -370,7 +478,10 @@ mod tests {
370478
#[test]
371479
fn insert_single_item() {
372480
let mut leaf = CompressedLeafNode::<i32, i32>::new(8);
373-
assert!(leaf.insert(42, 100).is_ok());
481+
match leaf.insert(42, 100) {
482+
InsertResult::Updated(None) => {}, // New insertion
483+
_ => panic!("Expected new insertion"),
484+
}
374485
assert_eq!(leaf.len(), 1);
375486
assert_eq!(leaf.get(&42), Some(&100));
376487
}
@@ -441,7 +552,10 @@ mod tests {
441552
fn insert_multiple_sorted() {
442553
let mut leaf = CompressedLeafNode::<i32, i32>::new(8);
443554
for i in 0..5 {
444-
assert!(leaf.insert(i, i * 10).is_ok());
555+
match leaf.insert(i, i * 10) {
556+
InsertResult::Updated(None) => {}, // New insertion
557+
_ => panic!("Expected new insertion"),
558+
}
445559
}
446560
assert_eq!(leaf.len(), 5);
447561

@@ -457,7 +571,10 @@ mod tests {
457571
let keys = [5, 1, 8, 3, 7];
458572

459573
for &key in &keys {
460-
assert!(leaf.insert(key, key * 10).is_ok());
574+
match leaf.insert(key, key * 10) {
575+
InsertResult::Updated(None) => {}, // New insertion
576+
_ => panic!("Expected new insertion"),
577+
}
461578
}
462579
assert_eq!(leaf.len(), 5);
463580

@@ -482,12 +599,20 @@ mod tests {
482599
let mut leaf = CompressedLeafNode::<i32, i32>::new(8);
483600

484601
// Insert initial value
485-
assert!(leaf.insert(42, 100).is_ok());
602+
match leaf.insert(42, 100) {
603+
InsertResult::Updated(None) => {}, // New insertion
604+
_ => panic!("Expected new insertion"),
605+
}
486606
assert_eq!(leaf.len(), 1);
487607
assert_eq!(leaf.get(&42), Some(&100));
488608

489609
// Insert same key with different value (should update)
490-
assert!(leaf.insert(42, 200).is_ok());
610+
match leaf.insert(42, 200) {
611+
InsertResult::Updated(Some(old_value)) => {
612+
assert_eq!(old_value, 100);
613+
},
614+
_ => panic!("Expected key update"),
615+
}
491616
assert_eq!(leaf.len(), 1); // Length shouldn't change
492617
assert_eq!(leaf.get(&42), Some(&200)); // Value should be updated
493618
}
@@ -500,22 +625,45 @@ mod tests {
500625

501626
// Fill to capacity
502627
for i in 0..4 {
503-
assert!(leaf.insert(i, i * 10).is_ok());
628+
match leaf.insert(i, i * 10) {
629+
InsertResult::Updated(None) => {}, // New insertion
630+
_ => panic!("Expected new insertion"),
631+
}
504632
}
505633
assert!(leaf.is_full());
506634

507-
// Attempt overflow
508-
assert!(leaf.insert(99, 990).is_err());
635+
// Attempt overflow - should trigger split
636+
match leaf.insert(99, 990) {
637+
InsertResult::Split { old_value: None, new_node_data, separator_key } => {
638+
// Verify split occurred
639+
assert!(separator_key >= 0 && separator_key <= 99);
640+
// The new node should be a leaf
641+
match new_node_data {
642+
SplitNodeData::Leaf(_) => {},
643+
_ => panic!("Expected leaf split"),
644+
}
645+
},
646+
_ => panic!("Expected split when inserting beyond capacity"),
647+
}
509648
}
510649

511650
#[test]
512651
fn insert_comprehensive_edge_cases() {
513652
let mut leaf = CompressedLeafNode::<i32, i32>::new(10);
514653

515654
// Test inserting at boundaries
516-
assert!(leaf.insert(i32::MIN, -1000).is_ok());
517-
assert!(leaf.insert(i32::MAX, 1000).is_ok());
518-
assert!(leaf.insert(0, 0).is_ok());
655+
match leaf.insert(i32::MIN, -1000) {
656+
InsertResult::Updated(None) => {},
657+
_ => panic!("Expected new insertion"),
658+
}
659+
match leaf.insert(i32::MAX, 1000) {
660+
InsertResult::Updated(None) => {},
661+
_ => panic!("Expected new insertion"),
662+
}
663+
match leaf.insert(0, 0) {
664+
InsertResult::Updated(None) => {},
665+
_ => panic!("Expected new insertion"),
666+
}
519667
assert_eq!(leaf.len(), 3);
520668

521669
// Verify they're accessible
@@ -524,8 +672,14 @@ mod tests {
524672
assert_eq!(leaf.get(&0), Some(&0));
525673

526674
// Insert some values in between
527-
assert!(leaf.insert(-100, -100).is_ok());
528-
assert!(leaf.insert(100, 100).is_ok());
675+
match leaf.insert(-100, -100) {
676+
InsertResult::Updated(None) => {},
677+
_ => panic!("Expected new insertion"),
678+
}
679+
match leaf.insert(100, 100) {
680+
InsertResult::Updated(None) => {},
681+
_ => panic!("Expected new insertion"),
682+
}
529683
assert_eq!(leaf.len(), 5);
530684

531685
// Verify sorted order is maintained
@@ -538,8 +692,18 @@ mod tests {
538692
}
539693

540694
// Test updating boundary values
541-
assert!(leaf.insert(i32::MIN, -2000).is_ok());
542-
assert!(leaf.insert(i32::MAX, 2000).is_ok());
695+
match leaf.insert(i32::MIN, -2000) {
696+
InsertResult::Updated(Some(old_value)) => {
697+
assert_eq!(old_value, -1000);
698+
},
699+
_ => panic!("Expected key update"),
700+
}
701+
match leaf.insert(i32::MAX, 2000) {
702+
InsertResult::Updated(Some(old_value)) => {
703+
assert_eq!(old_value, 1000);
704+
},
705+
_ => panic!("Expected key update"),
706+
}
543707
assert_eq!(leaf.len(), 5); // Length shouldn't change
544708

545709
assert_eq!(leaf.get(&i32::MIN), Some(&-2000));
@@ -584,7 +748,10 @@ mod tests {
584748
#[should_panic] // Remove this when implementing
585749
fn remove_existing_key() {
586750
let mut leaf = CompressedLeafNode::<i32, i32>::new(8);
587-
leaf.insert(42, 100).unwrap();
751+
match leaf.insert(42, 100) {
752+
InsertResult::Updated(None) => {}, // New insertion
753+
_ => panic!("Expected new insertion"),
754+
}
588755

589756
assert_eq!(leaf.remove(&42), Some(100));
590757
assert_eq!(leaf.len(), 0);

0 commit comments

Comments
 (0)