unified records, keys

This commit is contained in:
bronku 2025-12-11 20:44:18 +01:00
parent 78132349d3
commit 16d04f3e7c
4 changed files with 69 additions and 189 deletions

View file

@ -45,7 +45,8 @@ where
} }
} }
pub fn insert(&mut self, key: i32, value: Record) { pub fn insert(&mut self, value: Record) {
let key = value[0];
let mut path = Vec::new(); let mut path = Vec::new();
let mut current_loc = self.root_loc; let mut current_loc = self.root_loc;
let mut current_node = self.storage.read_node(current_loc).unwrap(); let mut current_node = self.storage.read_node(current_loc).unwrap();
@ -194,19 +195,19 @@ mod tests {
use crate::storage::InMemoryStorage; use crate::storage::InMemoryStorage;
// Helper function to generate a large number of keys and values // Helper function to generate a large number of keys and values
fn generate_large_dataset(size: usize) -> (Vec<i32>, Vec<Record>) { fn generate_large_dataset(size: usize) -> Vec<Record> {
let keys: Vec<i32> = (1..=size as i32).collect(); let keys: Vec<i32> = (1..=size as i32).collect();
let values: Vec<Record> = keys.iter().map(|&k| [k; 6]).collect(); let values: Vec<Record> = keys.iter().map(|&k| [k; 7]).collect();
(keys, values) values
} }
// Helper function to generate random keys and values // Helper function to generate random keys and values
fn generate_random_dataset(size: usize) -> (Vec<i32>, Vec<Record>) { fn generate_random_dataset(size: usize) -> Vec<Record> {
use rand::Rng; use rand::Rng;
let mut rng = rand::rng(); let mut rng = rand::rng();
let keys: Vec<i32> = (0..size).map(|_| rng.random_range(1..10000)).collect(); let keys: Vec<i32> = (0..size).map(|_| rng.random_range(1..10000)).collect();
let values: Vec<Record> = keys.iter().map(|&k| [k; 6]).collect(); let values: Vec<Record> = keys.iter().map(|&k| [k; 7]).collect();
(keys, values) values
} }
#[test] #[test]
@ -220,50 +221,27 @@ mod tests {
fn test_insert_and_find() { fn test_insert_and_find() {
let storage = InMemoryStorage::new(); let storage = InMemoryStorage::new();
let mut tree = BPlusTree::open(storage); let mut tree = BPlusTree::open(storage);
let key = 1; let value = [1, 1, 2, 3, 4, 5, 6]; // Example Record as [i32; 6]
let value = [1, 2, 3, 4, 5, 6]; // Example Record as [i32; 6] tree.insert(value);
tree.insert(key, value); assert_eq!(tree.find(value[0]), Some(value));
assert_eq!(tree.find(key), Some(value));
} }
#[test] #[test]
fn test_multiple_inserts_and_finds() { fn test_multiple_inserts_and_finds() {
let storage = InMemoryStorage::new(); let storage = InMemoryStorage::new();
let mut tree = BPlusTree::open(storage); let mut tree = BPlusTree::open(storage);
let keys = [1, 2, 3, 4, 5];
let values = [ let values = [
[1, 2, 3, 4, 5, 6], [1, 1, 2, 3, 4, 5, 6],
[7, 8, 9, 10, 11, 12], [2, 7, 8, 9, 10, 11, 12],
[13, 14, 15, 16, 17, 18], [3, 13, 14, 15, 16, 17, 18],
[19, 20, 21, 22, 23, 24], [4, 19, 20, 21, 22, 23, 24],
[25, 26, 27, 28, 29, 30], [5, 25, 26, 27, 28, 29, 30],
]; ];
for (i, key) in keys.iter().enumerate() { for rec in values {
tree.insert(*key, values[i]); tree.insert(rec);
} }
for (i, key) in keys.iter().enumerate() { for rec in values {
assert_eq!(tree.find(*key), Some(values[i])); assert_eq!(tree.find(rec[0]), Some(rec));
}
}
#[test]
fn test_leaf_split() {
let storage = InMemoryStorage::new();
let mut tree = BPlusTree::open(storage);
let keys = [1, 2, 3, 4, 5]; // Assuming MAX_KEYS is 4, this will trigger a split
let values = [
[1, 2, 3, 4, 5, 6],
[7, 8, 9, 10, 11, 12],
[13, 14, 15, 16, 17, 18],
[19, 20, 21, 22, 23, 24],
[25, 26, 27, 28, 29, 30],
];
for (i, key) in keys.iter().enumerate() {
tree.insert(*key, values[i]);
}
// Verify that all keys can still be found after splits
for (i, key) in keys.iter().enumerate() {
assert_eq!(tree.find(*key), Some(values[i]));
} }
} }
@ -271,27 +249,24 @@ mod tests {
fn test_internal_split() { fn test_internal_split() {
let storage = InMemoryStorage::new(); let storage = InMemoryStorage::new();
let mut tree = BPlusTree::open(storage); let mut tree = BPlusTree::open(storage);
// Insert enough keys to trigger internal splits
let keys = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let values = [ let values = [
[1, 2, 3, 4, 5, 6], [1, 1, 2, 3, 4, 5, 6],
[7, 8, 9, 10, 11, 12], [2, 7, 8, 9, 10, 11, 12],
[13, 14, 15, 16, 17, 18], [3, 13, 14, 15, 16, 17, 18],
[19, 20, 21, 22, 23, 24], [4, 19, 20, 21, 22, 23, 24],
[25, 26, 27, 28, 29, 30], [5, 25, 26, 27, 28, 29, 30],
[31, 32, 33, 34, 35, 36], [6, 31, 32, 33, 34, 35, 36],
[37, 38, 39, 40, 41, 42], [7, 37, 38, 39, 40, 41, 42],
[43, 44, 45, 46, 47, 48], [8, 43, 44, 45, 46, 47, 48],
[49, 50, 51, 52, 53, 54], [9, 49, 50, 51, 52, 53, 54],
[55, 56, 57, 58, 59, 60], [10, 55, 56, 57, 58, 59, 60],
[61, 62, 63, 64, 65, 66], [11, 61, 62, 63, 64, 65, 66],
]; ];
for (i, key) in keys.iter().enumerate() { for rec in values {
tree.insert(*key, values[i]); tree.insert(rec);
} }
// Verify that all keys can still be found after splits for rec in values {
for (i, key) in keys.iter().enumerate() { assert_eq!(tree.find(rec[0]), Some(rec));
assert_eq!(tree.find(*key), Some(values[i]));
} }
} }
@ -300,11 +275,11 @@ mod tests {
let storage = InMemoryStorage::new(); let storage = InMemoryStorage::new();
let mut tree = BPlusTree::open(storage); let mut tree = BPlusTree::open(storage);
let key = 1; let key = 1;
let initial_value = [1, 2, 3, 4, 5, 6]; let initial_value = [key, 1, 2, 3, 4, 5, 6];
let updated_value = [7, 8, 9, 10, 11, 12]; let updated_value = [key, 7, 8, 9, 10, 11, 12];
tree.insert(key, initial_value); tree.insert(initial_value);
assert_eq!(tree.find(key), Some(initial_value)); assert_eq!(tree.find(key), Some(initial_value));
tree.insert(key, updated_value); tree.insert(updated_value);
assert_eq!(tree.find(key), Some(updated_value)); assert_eq!(tree.find(key), Some(updated_value));
} }
@ -319,20 +294,18 @@ mod tests {
fn test_out_of_order_inserts() { fn test_out_of_order_inserts() {
let storage = InMemoryStorage::new(); let storage = InMemoryStorage::new();
let mut tree = BPlusTree::open(storage); let mut tree = BPlusTree::open(storage);
let keys = [5, 3, 1, 4, 2];
let values = [ let values = [
[1, 2, 3, 4, 5, 6], [5, 1, 2, 3, 4, 5, 6],
[7, 8, 9, 10, 11, 12], [3, 7, 8, 9, 10, 11, 12],
[13, 14, 15, 16, 17, 18], [1, 13, 14, 15, 16, 17, 18],
[19, 20, 21, 22, 23, 24], [4, 19, 20, 21, 22, 23, 24],
[25, 26, 27, 28, 29, 30], [2, 25, 26, 27, 28, 29, 30],
]; ];
for (i, key) in keys.iter().enumerate() { for rec in values {
tree.insert(*key, values[i]); tree.insert(rec);
} }
// Verify that all keys can be found for rec in values {
for (i, key) in keys.iter().enumerate() { assert_eq!(tree.find(rec[0]), Some(rec));
assert_eq!(tree.find(*key), Some(values[i]));
} }
} }
@ -340,65 +313,13 @@ mod tests {
fn test_large_number_of_inserts() { fn test_large_number_of_inserts() {
let storage = InMemoryStorage::new(); let storage = InMemoryStorage::new();
let mut tree = BPlusTree::open(storage); let mut tree = BPlusTree::open(storage);
let num_keys = 100; let num_keys = 100000;
let keys: Vec<i32> = (1..=num_keys).collect(); let values = generate_large_dataset(num_keys);
let values: Vec<Record> = (1..=num_keys) for rec in &values {
.map(|i| [i, i + 1, i + 2, i + 3, i + 4, i + 5]) tree.insert(*rec);
.collect();
for (i, key) in keys.iter().enumerate() {
tree.insert(*key, values[i]);
} }
// Verify that all keys can be found for rec in &values {
for (i, key) in keys.iter().enumerate() { assert_eq!(tree.find(rec[0]), Some(*rec));
assert_eq!(tree.find(*key), Some(values[i]));
}
}
#[test]
fn test_duplicate_keys() {
let storage = InMemoryStorage::new();
let mut tree = BPlusTree::open(storage);
let key = 1;
let initial_value = [1, 2, 3, 4, 5, 6];
let updated_value = [7, 8, 9, 10, 11, 12];
tree.insert(key, initial_value);
assert_eq!(tree.find(key), Some(initial_value));
tree.insert(key, updated_value);
assert_eq!(tree.find(key), Some(updated_value));
}
#[test]
fn test_recursive_splitting_up_to_root() {
let storage = InMemoryStorage::new();
let mut tree = BPlusTree::open(storage);
// Insert enough keys to cause multiple splits, including root split
let keys = (1..=20).collect::<Vec<i32>>();
let values: Vec<Record> = keys.iter().map(|&k| [k; 6]).collect();
for (i, key) in keys.iter().enumerate() {
tree.insert(*key, values[i]);
}
// Verify all keys are present
for (i, key) in keys.iter().enumerate() {
assert_eq!(tree.find(*key), Some(values[i]));
}
}
#[test]
fn test_large_dataset() {
let storage = InMemoryStorage::new();
let mut tree = BPlusTree::open(storage);
let (keys, values) = generate_large_dataset(10000);
for (i, key) in keys.iter().enumerate() {
tree.insert(*key, values[i]);
}
// Verify all keys are present
for (i, key) in keys.iter().enumerate() {
assert_eq!(tree.find(*key), Some(values[i]));
} }
} }
@ -407,67 +328,27 @@ mod tests {
let storage = InMemoryStorage::new(); let storage = InMemoryStorage::new();
let mut tree = BPlusTree::open(storage); let mut tree = BPlusTree::open(storage);
// Test with minimum and maximum i32 values let min_value = [i32::MIN; 7];
let min_key = i32::MIN; let max_value = [i32::MAX; 7];
let max_key = i32::MAX;
let min_value = [i32::MIN; 6];
let max_value = [i32::MAX; 6];
tree.insert(min_key, min_value); tree.insert(min_value);
tree.insert(max_key, max_value); tree.insert(max_value);
assert_eq!(tree.find(min_key), Some(min_value)); assert_eq!(tree.find(min_value[0]), Some(min_value));
assert_eq!(tree.find(max_key), Some(max_value)); assert_eq!(tree.find(max_value[0]), Some(max_value));
}
#[test]
fn test_sequential_insertions() {
let storage = InMemoryStorage::new();
let mut tree = BPlusTree::open(storage);
let (keys, values) = generate_large_dataset(100);
for (i, key) in keys.iter().enumerate() {
tree.insert(*key, values[i]);
}
// Verify all keys are present
for (i, key) in keys.iter().enumerate() {
assert_eq!(tree.find(*key), Some(values[i]));
}
} }
#[test] #[test]
fn test_random_insertions() { fn test_random_insertions() {
let storage = InMemoryStorage::new(); let storage = InMemoryStorage::new();
let mut tree = BPlusTree::open(storage); let mut tree = BPlusTree::open(storage);
let (keys, values) = generate_random_dataset(100); let values = generate_random_dataset(10000);
for (i, key) in keys.iter().enumerate() { for rec in &values {
tree.insert(*key, values[i]); tree.insert(*rec);
} }
for rec in &values {
// Verify all keys are present assert_eq!(tree.find(rec[0]), Some(*rec));
for (i, key) in keys.iter().enumerate() {
assert_eq!(tree.find(*key), Some(values[i]));
}
}
#[test]
fn test_node_splitting_and_balance() {
let storage = InMemoryStorage::new();
let mut tree = BPlusTree::open(storage);
// Insert keys that will cause multiple splits
let keys = (1..=50).collect::<Vec<i32>>();
let values: Vec<Record> = keys.iter().map(|&k| [k; 6]).collect();
for (i, key) in keys.iter().enumerate() {
tree.insert(*key, values[i]);
}
// Verify all keys are present and tree is balanced
for (i, key) in keys.iter().enumerate() {
assert_eq!(tree.find(*key), Some(values[i]));
} }
} }
} }

View file

@ -11,8 +11,8 @@ fn main() {
let mut tree = BPlusTree::open(storage); let mut tree = BPlusTree::open(storage);
// Insert some key-value pairs // Insert some key-value pairs
tree.insert(1, [0, 0, 0, 0, 0, 0]); tree.insert([1, 0, 0, 0, 0, 0, 0]);
tree.insert(2, [1, 0, 1, 0, 1, 0]); tree.insert([2, 1, 0, 1, 0, 1, 0]);
// Find a key // Find a key
let value = tree.find(2); let value = tree.find(2);

View file

@ -29,5 +29,3 @@ pub struct InternalNode {
pub keys: Vec<i32>, pub keys: Vec<i32>,
pub children: Vec<usize>, pub children: Vec<usize>,
} }

View file

@ -1 +1,2 @@
pub type Record = [i32; 6]; // 0 - key, 1 - x, 2 ..=6 - a
pub type Record = [i32; 7];