store: redb indexes offsets into capnp log, not full nodes
Restructure store module with clearer file names: - persist.rs → capnp.rs (capnp log IO) - db.rs → index.rs (redb index operations) redb now stores key → offset mapping, not serialized nodes. Mutations record the offset after appending to capnp log. rebuild_index scans capnp log to reconstruct the index. The HashMap still exists for now; next step is to use the index for lookups and remove it. Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
parent
9309de68fc
commit
f413a853d8
5 changed files with 225 additions and 149 deletions
104
src/hippocampus/store/index.rs
Normal file
104
src/hippocampus/store/index.rs
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
// 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<Database> {
|
||||
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<Option<u64>> {
|
||||
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<bool> {
|
||||
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<Option<String>> {
|
||||
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<u64> {
|
||||
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<Vec<String>> {
|
||||
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)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue