port radixtree to rust
This commit is contained in:
parent
e62e0a125a
commit
dc8c887026
@ -12,8 +12,7 @@ mod serialize;
|
||||
pub use error::Error;
|
||||
pub use node::{Node, NodeRef};
|
||||
|
||||
use ourdb::{OurDB, OurDBConfig, OurDBSetArgs};
|
||||
use std::path::PathBuf;
|
||||
use ourdb::OurDB;
|
||||
|
||||
/// RadixTree represents a radix tree data structure with persistent storage.
|
||||
pub struct RadixTree {
|
||||
@ -37,8 +36,7 @@ impl RadixTree {
|
||||
///
|
||||
/// Returns an error if the database cannot be created or opened
|
||||
pub fn new(path: &str, reset: bool) -> Result<Self, Error> {
|
||||
// Implementation will be provided in operations.rs
|
||||
unimplemented!()
|
||||
operations::new_radix_tree(path, reset)
|
||||
}
|
||||
|
||||
/// Sets a key-value pair in the tree.
|
||||
@ -52,8 +50,7 @@ impl RadixTree {
|
||||
///
|
||||
/// Returns an error if the operation fails
|
||||
pub fn set(&mut self, key: &str, value: Vec<u8>) -> Result<(), Error> {
|
||||
// Implementation will be provided in operations.rs
|
||||
unimplemented!()
|
||||
operations::set(self, key, value)
|
||||
}
|
||||
|
||||
/// Gets a value by key from the tree.
|
||||
@ -70,8 +67,7 @@ impl RadixTree {
|
||||
///
|
||||
/// Returns an error if the key is not found or the operation fails
|
||||
pub fn get(&mut self, key: &str) -> Result<Vec<u8>, Error> {
|
||||
// Implementation will be provided in operations.rs
|
||||
unimplemented!()
|
||||
operations::get(self, key)
|
||||
}
|
||||
|
||||
/// Updates the value at a given key prefix.
|
||||
@ -85,8 +81,7 @@ impl RadixTree {
|
||||
///
|
||||
/// Returns an error if the prefix is not found or the operation fails
|
||||
pub fn update(&mut self, prefix: &str, new_value: Vec<u8>) -> Result<(), Error> {
|
||||
// Implementation will be provided in operations.rs
|
||||
unimplemented!()
|
||||
operations::update(self, prefix, new_value)
|
||||
}
|
||||
|
||||
/// Deletes a key from the tree.
|
||||
@ -99,8 +94,7 @@ impl RadixTree {
|
||||
///
|
||||
/// Returns an error if the key is not found or the operation fails
|
||||
pub fn delete(&mut self, key: &str) -> Result<(), Error> {
|
||||
// Implementation will be provided in operations.rs
|
||||
unimplemented!()
|
||||
operations::delete(self, key)
|
||||
}
|
||||
|
||||
/// Lists all keys with a given prefix.
|
||||
@ -117,8 +111,7 @@ impl RadixTree {
|
||||
///
|
||||
/// Returns an error if the operation fails
|
||||
pub fn list(&mut self, prefix: &str) -> Result<Vec<String>, Error> {
|
||||
// Implementation will be provided in operations.rs
|
||||
unimplemented!()
|
||||
operations::list(self, prefix)
|
||||
}
|
||||
|
||||
/// Gets all values for keys with a given prefix.
|
||||
@ -135,7 +128,6 @@ impl RadixTree {
|
||||
///
|
||||
/// Returns an error if the operation fails
|
||||
pub fn getall(&mut self, prefix: &str) -> Result<Vec<Vec<u8>>, Error> {
|
||||
// Implementation will be provided in operations.rs
|
||||
unimplemented!()
|
||||
operations::getall(self, prefix)
|
||||
}
|
||||
}
|
||||
|
@ -3,20 +3,26 @@
|
||||
use crate::error::Error;
|
||||
use crate::node::{Node, NodeRef};
|
||||
use crate::RadixTree;
|
||||
use crate::serialize::get_common_prefix;
|
||||
use ourdb::{OurDB, OurDBConfig, OurDBSetArgs};
|
||||
use std::path::PathBuf;
|
||||
|
||||
|
||||
impl RadixTree {
|
||||
/// Creates a new radix tree with the specified database path.
|
||||
pub fn new(path: &str, reset: bool) -> Result<Self, Error> {
|
||||
/// Creates a new radix tree with the specified database path.
|
||||
pub fn new_radix_tree(path: &str, reset: bool) -> Result<RadixTree, Error> {
|
||||
let config = OurDBConfig {
|
||||
record_size_max: 1024 * 4, // 4KB max record size
|
||||
path: PathBuf::from(path),
|
||||
incremental_mode: true,
|
||||
reset,
|
||||
..Default::default()
|
||||
file_size: Some(1024 * 1024), // 1MB file size
|
||||
keysize: Some(4), // Default key size
|
||||
};
|
||||
|
||||
let db = OurDB::new(path, config)?;
|
||||
let mut db = OurDB::new(config)?;
|
||||
|
||||
// If reset is true, we would clear the database
|
||||
// Since OurDB doesn't have a reset method, we'll handle it by
|
||||
// creating a fresh database when reset is true
|
||||
// We'll implement this by checking if it's a new database (next_id == 1)
|
||||
|
||||
let root_id = if db.get_next_id()? == 1 {
|
||||
// Create a new root node
|
||||
@ -34,44 +40,28 @@ impl RadixTree {
|
||||
1 // Root node always has ID 1
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
Ok(RadixTree {
|
||||
db,
|
||||
root_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper function to get a node from the database.
|
||||
pub(crate) fn get_node(&mut self, node_id: u32) -> Result<Node, Error> {
|
||||
let data = self.db.get(node_id)?;
|
||||
Node::deserialize(&data)
|
||||
}
|
||||
|
||||
/// Helper function to save a node to the database.
|
||||
pub(crate) fn save_node(&mut self, node_id: Option<u32>, node: &Node) -> Result<u32, Error> {
|
||||
let data = node.serialize();
|
||||
let args = OurDBSetArgs {
|
||||
id: node_id,
|
||||
data: &data,
|
||||
};
|
||||
Ok(self.db.set(args)?)
|
||||
}
|
||||
|
||||
/// Sets a key-value pair in the tree.
|
||||
pub fn set(&mut self, key: &str, value: Vec<u8>) -> Result<(), Error> {
|
||||
let mut current_id = self.root_id;
|
||||
/// Sets a key-value pair in the tree.
|
||||
pub fn set(tree: &mut RadixTree, key: &str, value: Vec<u8>) -> Result<(), Error> {
|
||||
let mut current_id = tree.root_id;
|
||||
let mut offset = 0;
|
||||
|
||||
// Handle empty key case
|
||||
if key.is_empty() {
|
||||
let mut root_node = self.get_node(current_id)?;
|
||||
let mut root_node = tree.get_node(current_id)?;
|
||||
root_node.is_leaf = true;
|
||||
root_node.value = value;
|
||||
self.save_node(Some(current_id), &root_node)?;
|
||||
tree.save_node(Some(current_id), &root_node)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
while offset < key.len() {
|
||||
let mut node = self.get_node(current_id)?;
|
||||
let mut node = tree.get_node(current_id)?;
|
||||
|
||||
// Find matching child
|
||||
let mut matched_child = None;
|
||||
@ -92,7 +82,7 @@ impl RadixTree {
|
||||
is_leaf: true,
|
||||
};
|
||||
|
||||
let new_id = self.save_node(None, &new_node)?;
|
||||
let new_id = tree.save_node(None, &new_node)?;
|
||||
|
||||
// Create new child reference and update parent node
|
||||
node.children.push(NodeRef {
|
||||
@ -100,7 +90,7 @@ impl RadixTree {
|
||||
node_id: new_id,
|
||||
});
|
||||
|
||||
self.save_node(Some(current_id), &node)?;
|
||||
tree.save_node(Some(current_id), &node)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@ -109,7 +99,7 @@ impl RadixTree {
|
||||
|
||||
if common_prefix.len() < child.key_part.len() {
|
||||
// Split existing node
|
||||
let mut child_node = self.get_node(child.node_id)?;
|
||||
let child_node = tree.get_node(child.node_id)?;
|
||||
|
||||
// Create new intermediate node
|
||||
let new_node = Node {
|
||||
@ -118,14 +108,14 @@ impl RadixTree {
|
||||
children: child_node.children.clone(),
|
||||
is_leaf: child_node.is_leaf,
|
||||
};
|
||||
let new_id = self.save_node(None, &new_node)?;
|
||||
let new_id = tree.save_node(None, &new_node)?;
|
||||
|
||||
// Update current node
|
||||
node.children[child_index] = NodeRef {
|
||||
key_part: common_prefix.to_string(),
|
||||
node_id: new_id,
|
||||
};
|
||||
self.save_node(Some(current_id), &node)?;
|
||||
tree.save_node(Some(current_id), &node)?;
|
||||
|
||||
// Update child node reference
|
||||
child.node_id = new_id;
|
||||
@ -133,10 +123,10 @@ impl RadixTree {
|
||||
|
||||
if offset + common_prefix.len() == key.len() {
|
||||
// Update value at existing node
|
||||
let mut child_node = self.get_node(child.node_id)?;
|
||||
let mut child_node = tree.get_node(child.node_id)?;
|
||||
child_node.value = value;
|
||||
child_node.is_leaf = true;
|
||||
self.save_node(Some(child.node_id), &child_node)?;
|
||||
tree.save_node(Some(child.node_id), &child_node)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@ -145,30 +135,30 @@ impl RadixTree {
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a value by key from the tree.
|
||||
pub fn get(&mut self, key: &str) -> Result<Vec<u8>, Error> {
|
||||
let mut current_id = self.root_id;
|
||||
/// Gets a value by key from the tree.
|
||||
pub fn get(tree: &mut RadixTree, key: &str) -> Result<Vec<u8>, Error> {
|
||||
let mut current_id = tree.root_id;
|
||||
let mut offset = 0;
|
||||
|
||||
// Handle empty key case
|
||||
if key.is_empty() {
|
||||
let root_node = self.get_node(current_id)?;
|
||||
let root_node = tree.get_node(current_id)?;
|
||||
if root_node.is_leaf {
|
||||
return Ok(root_node.value);
|
||||
return Ok(root_node.value.clone());
|
||||
}
|
||||
return Err(Error::KeyNotFound(key.to_string()));
|
||||
}
|
||||
|
||||
while offset < key.len() {
|
||||
let node = self.get_node(current_id)?;
|
||||
let node = tree.get_node(current_id)?;
|
||||
|
||||
let mut found = false;
|
||||
for child in &node.children {
|
||||
if key[offset..].starts_with(&child.key_part) {
|
||||
if offset + child.key_part.len() == key.len() {
|
||||
let child_node = self.get_node(child.node_id)?;
|
||||
let child_node = tree.get_node(child.node_id)?;
|
||||
if child_node.is_leaf {
|
||||
return Ok(child_node.value);
|
||||
}
|
||||
@ -186,11 +176,11 @@ impl RadixTree {
|
||||
}
|
||||
|
||||
Err(Error::KeyNotFound(key.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates the value at a given key prefix.
|
||||
pub fn update(&mut self, prefix: &str, new_value: Vec<u8>) -> Result<(), Error> {
|
||||
let mut current_id = self.root_id;
|
||||
/// Updates the value at a given key prefix.
|
||||
pub fn update(tree: &mut RadixTree, prefix: &str, new_value: Vec<u8>) -> Result<(), Error> {
|
||||
let mut current_id = tree.root_id;
|
||||
let mut offset = 0;
|
||||
|
||||
// Handle empty prefix case
|
||||
@ -199,18 +189,18 @@ impl RadixTree {
|
||||
}
|
||||
|
||||
while offset < prefix.len() {
|
||||
let node = self.get_node(current_id)?;
|
||||
let node = tree.get_node(current_id)?;
|
||||
|
||||
let mut found = false;
|
||||
for child in &node.children {
|
||||
if prefix[offset..].starts_with(&child.key_part) {
|
||||
if offset + child.key_part.len() == prefix.len() {
|
||||
// Found exact prefix match
|
||||
let mut child_node = self.get_node(child.node_id)?;
|
||||
let mut child_node = tree.get_node(child.node_id)?;
|
||||
if child_node.is_leaf {
|
||||
// Update the value
|
||||
child_node.value = new_value;
|
||||
self.save_node(Some(child.node_id), &child_node)?;
|
||||
tree.save_node(Some(child.node_id), &child_node)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
@ -227,17 +217,30 @@ impl RadixTree {
|
||||
}
|
||||
|
||||
Err(Error::PrefixNotFound(prefix.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Deletes a key from the tree.
|
||||
pub fn delete(&mut self, key: &str) -> Result<(), Error> {
|
||||
let mut current_id = self.root_id;
|
||||
/// Deletes a key from the tree.
|
||||
pub fn delete(tree: &mut RadixTree, key: &str) -> Result<(), Error> {
|
||||
let mut current_id = tree.root_id;
|
||||
let mut offset = 0;
|
||||
let mut path = Vec::new();
|
||||
|
||||
// Handle empty key case
|
||||
if key.is_empty() {
|
||||
let mut root_node = tree.get_node(current_id)?;
|
||||
if !root_node.is_leaf {
|
||||
return Err(Error::KeyNotFound(key.to_string()));
|
||||
}
|
||||
// For the root node, we just mark it as non-leaf
|
||||
root_node.is_leaf = false;
|
||||
root_node.value = Vec::new();
|
||||
tree.save_node(Some(current_id), &root_node)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Find the node to delete
|
||||
while offset < key.len() {
|
||||
let node = self.get_node(current_id)?;
|
||||
let node = tree.get_node(current_id)?;
|
||||
|
||||
let mut found = false;
|
||||
for child in &node.children {
|
||||
@ -249,7 +252,7 @@ impl RadixTree {
|
||||
|
||||
// Check if we've matched the full key
|
||||
if offset == key.len() {
|
||||
let child_node = self.get_node(child.node_id)?;
|
||||
let child_node = tree.get_node(child.node_id)?;
|
||||
if child_node.is_leaf {
|
||||
found = true;
|
||||
break;
|
||||
@ -269,20 +272,20 @@ impl RadixTree {
|
||||
}
|
||||
|
||||
// Get the node to delete
|
||||
let mut last_node = self.get_node(path.last().unwrap().node_id)?;
|
||||
let mut last_node = tree.get_node(path.last().unwrap().node_id)?;
|
||||
|
||||
// If the node has children, just mark it as non-leaf
|
||||
if !last_node.children.is_empty() {
|
||||
last_node.is_leaf = false;
|
||||
last_node.value = Vec::new();
|
||||
self.save_node(Some(path.last().unwrap().node_id), &last_node)?;
|
||||
tree.save_node(Some(path.last().unwrap().node_id), &last_node)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// If node has no children, remove it from parent
|
||||
if path.len() > 1 {
|
||||
let parent_id = path[path.len() - 2].node_id;
|
||||
let mut parent_node = self.get_node(parent_id)?;
|
||||
let mut parent_node = tree.get_node(parent_id)?;
|
||||
|
||||
// Find and remove the child from parent
|
||||
for i in 0..parent_node.children.len() {
|
||||
@ -292,33 +295,139 @@ impl RadixTree {
|
||||
}
|
||||
}
|
||||
|
||||
self.save_node(Some(parent_id), &parent_node)?;
|
||||
tree.save_node(Some(parent_id), &parent_node)?;
|
||||
|
||||
// Delete the node from the database
|
||||
self.db.delete(path.last().unwrap().node_id)?;
|
||||
tree.db.delete(path.last().unwrap().node_id)?;
|
||||
} else {
|
||||
// If this is a direct child of the root, just mark it as non-leaf
|
||||
last_node.is_leaf = false;
|
||||
last_node.value = Vec::new();
|
||||
self.save_node(Some(path.last().unwrap().node_id), &last_node)?;
|
||||
tree.save_node(Some(path.last().unwrap().node_id), &last_node)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Lists all keys with a given prefix.
|
||||
pub fn list(&mut self, prefix: &str) -> Result<Vec<String>, Error> {
|
||||
/// Lists all keys with a given prefix.
|
||||
pub fn list(tree: &mut RadixTree, prefix: &str) -> Result<Vec<String>, Error> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
// Handle empty prefix case - will return all keys
|
||||
if prefix.is_empty() {
|
||||
self.collect_all_keys(self.root_id, "", &mut result)?;
|
||||
collect_all_keys(tree, tree.root_id, "", &mut result)?;
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
// Start from the root and find all matching keys
|
||||
self.find_keys_with_prefix(self.root_id, "", prefix, &mut result)?;
|
||||
find_keys_with_prefix(tree, tree.root_id, "", prefix, &mut result)?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Helper function to find all keys with a given prefix.
|
||||
fn find_keys_with_prefix(
|
||||
tree: &mut RadixTree,
|
||||
node_id: u32,
|
||||
current_path: &str,
|
||||
prefix: &str,
|
||||
result: &mut Vec<String>,
|
||||
) -> Result<(), Error> {
|
||||
let node = tree.get_node(node_id)?;
|
||||
|
||||
// If the current path already matches or exceeds the prefix length
|
||||
if current_path.len() >= prefix.len() {
|
||||
// Check if the current path starts with the prefix
|
||||
if current_path.starts_with(prefix) {
|
||||
// If this is a leaf node, add it to the results
|
||||
if node.is_leaf {
|
||||
result.push(current_path.to_string());
|
||||
}
|
||||
|
||||
// Collect all keys from this subtree
|
||||
for child in &node.children {
|
||||
let child_path = format!("{}{}", current_path, child.key_part);
|
||||
find_keys_with_prefix(tree, child.node_id, &child_path, prefix, result)?;
|
||||
}
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Current path is shorter than the prefix, continue searching
|
||||
for child in &node.children {
|
||||
let child_path = format!("{}{}", current_path, child.key_part);
|
||||
|
||||
// Check if this child's path could potentially match the prefix
|
||||
if prefix.starts_with(current_path) {
|
||||
// The prefix starts with the current path, so we need to check if
|
||||
// the child's key_part matches the next part of the prefix
|
||||
let prefix_remainder = &prefix[current_path.len()..];
|
||||
|
||||
// If the prefix remainder starts with the child's key_part or vice versa
|
||||
if prefix_remainder.starts_with(&child.key_part)
|
||||
|| (child.key_part.starts_with(prefix_remainder)
|
||||
&& child.key_part.len() >= prefix_remainder.len()) {
|
||||
find_keys_with_prefix(tree, child.node_id, &child_path, prefix, result)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Helper function to recursively collect all keys under a node.
|
||||
fn collect_all_keys(
|
||||
tree: &mut RadixTree,
|
||||
node_id: u32,
|
||||
current_path: &str,
|
||||
result: &mut Vec<String>,
|
||||
) -> Result<(), Error> {
|
||||
let node = tree.get_node(node_id)?;
|
||||
|
||||
// If this node is a leaf, add its path to the result
|
||||
if node.is_leaf {
|
||||
result.push(current_path.to_string());
|
||||
}
|
||||
|
||||
// Recursively collect keys from all children
|
||||
for child in &node.children {
|
||||
let child_path = format!("{}{}", current_path, child.key_part);
|
||||
collect_all_keys(tree, child.node_id, &child_path, result)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Gets all values for keys with a given prefix.
|
||||
pub fn getall(tree: &mut RadixTree, prefix: &str) -> Result<Vec<Vec<u8>>, Error> {
|
||||
// Get all matching keys
|
||||
let keys = list(tree, prefix)?;
|
||||
|
||||
// Get values for each key
|
||||
let mut values = Vec::new();
|
||||
for key in keys {
|
||||
if let Ok(value) = get(tree, &key) {
|
||||
values.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(values)
|
||||
}
|
||||
|
||||
impl RadixTree {
|
||||
/// Helper function to get a node from the database.
|
||||
pub(crate) fn get_node(&mut self, node_id: u32) -> Result<Node, Error> {
|
||||
let data = self.db.get(node_id)?;
|
||||
Node::deserialize(&data)
|
||||
}
|
||||
|
||||
/// Helper function to save a node to the database.
|
||||
pub(crate) fn save_node(&mut self, node_id: Option<u32>, node: &Node) -> Result<u32, Error> {
|
||||
let data = node.serialize();
|
||||
let args = OurDBSetArgs {
|
||||
id: node_id,
|
||||
data: &data,
|
||||
};
|
||||
Ok(self.db.set(args)?)
|
||||
}
|
||||
|
||||
/// Helper function to find all keys with a given prefix.
|
||||
@ -393,33 +502,6 @@ impl RadixTree {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Gets all values for keys with a given prefix.
|
||||
pub fn getall(&mut self, prefix: &str) -> Result<Vec<Vec<u8>>, Error> {
|
||||
// Get all matching keys
|
||||
let keys = self.list(prefix)?;
|
||||
|
||||
// Get values for each key
|
||||
let mut values = Vec::new();
|
||||
for key in keys {
|
||||
if let Ok(value) = self.get(&key) {
|
||||
values.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(values)
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper function to get the common prefix of two strings.
|
||||
fn get_common_prefix(a: &str, b: &str) -> String {
|
||||
let mut i = 0;
|
||||
let a_bytes = a.as_bytes();
|
||||
let b_bytes = b.as_bytes();
|
||||
|
||||
while i < a.len() && i < b.len() && a_bytes[i] == b_bytes[i] {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
a[..i].to_string()
|
||||
}
|
||||
|
@ -2,8 +2,7 @@
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::node::{Node, NodeRef};
|
||||
use std::convert::TryInto;
|
||||
use std::io::{Cursor, Read, Write};
|
||||
use std::io::{Cursor, Read};
|
||||
use std::mem::size_of;
|
||||
|
||||
/// Current binary format version.
|
||||
@ -142,3 +141,16 @@ fn read_u32(cursor: &mut Cursor<&[u8]>) -> std::io::Result<u32> {
|
||||
|
||||
Ok(u32::from_le_bytes(bytes))
|
||||
}
|
||||
|
||||
/// Helper function to get the common prefix of two strings.
|
||||
pub fn get_common_prefix(a: &str, b: &str) -> String {
|
||||
let mut i = 0;
|
||||
let a_bytes = a.as_bytes();
|
||||
let b_bytes = b.as_bytes();
|
||||
|
||||
while i < a.len() && i < b.len() && a_bytes[i] == b_bytes[i] {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
a[..i].to_string()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user