// redb index tables // // capnp logs are source of truth; redb provides indexed access. // Tables: // nodes: key → offset in capnp log (u64) // uuid_to_key: [u8;16] → key // // To read a node: lookup offset in redb, seek in capnp file, deserialize. use anyhow::{Context, Result}; use redb::{Database, ReadableDatabase, ReadableTable, ReadableTableMetadata, TableDefinition}; use std::path::Path; // Table definitions - nodes maps key to byte offset in capnp log pub const NODES: TableDefinition<&str, u64> = TableDefinition::new("nodes"); pub const UUID_TO_KEY: TableDefinition<&[u8], &str> = TableDefinition::new("uuid_to_key"); /// Open or create the redb database, ensuring all tables exist. pub fn open_db(path: &Path) -> Result { let db = Database::create(path) .with_context(|| format!("create redb {}", path.display()))?; // Ensure tables exist by opening a write transaction let txn = db.begin_write()?; { let _ = txn.open_table(NODES)?; let _ = txn.open_table(UUID_TO_KEY)?; } txn.commit()?; Ok(db) } /// Record a node's location in the index. pub fn index_node(db: &Database, key: &str, offset: u64, uuid: &[u8; 16]) -> Result<()> { let txn = db.begin_write()?; { let mut nodes_table = txn.open_table(NODES)?; let mut uuid_table = txn.open_table(UUID_TO_KEY)?; nodes_table.insert(key, offset)?; uuid_table.insert(uuid.as_slice(), key)?; } txn.commit()?; Ok(()) } /// Get offset for a node by key. pub fn get_offset(db: &Database, key: &str) -> Result> { let txn = db.begin_read()?; let table = txn.open_table(NODES)?; Ok(table.get(key)?.map(|v| v.value())) } /// Check if a key exists in the index. pub fn contains_key(db: &Database, key: &str) -> Result { let txn = db.begin_read()?; let table = txn.open_table(NODES)?; Ok(table.get(key)?.is_some()) } /// Get key by uuid from redb. pub fn get_key_by_uuid(db: &Database, uuid: &[u8; 16]) -> Result> { let txn = db.begin_read()?; let table = txn.open_table(UUID_TO_KEY)?; match table.get(uuid.as_slice())? { Some(key) => Ok(Some(key.value().to_string())), None => Ok(None), } } /// Remove a node from the index. pub fn remove_node(db: &Database, key: &str, uuid: &[u8; 16]) -> Result<()> { let txn = db.begin_write()?; { let mut nodes_table = txn.open_table(NODES)?; let mut uuid_table = txn.open_table(UUID_TO_KEY)?; nodes_table.remove(key)?; uuid_table.remove(uuid.as_slice())?; } txn.commit()?; Ok(()) } /// Count nodes in the index. pub fn node_count(db: &Database) -> Result { let txn = db.begin_read()?; let table = txn.open_table(NODES)?; Ok(table.len()?) } /// Collect all keys from the index. pub fn all_keys(db: &Database) -> Result> { let txn = db.begin_read()?; let table = txn.open_table(NODES)?; let mut keys = Vec::new(); for entry in table.iter()? { let (key, _) = entry?; keys.push(key.value().to_string()); } Ok(keys) }