store: wire up redb updates on mutations

Mutations (upsert_node, upsert_provenance, delete_node, rename_node)
now update redb indices atomically with capnp log appends, under the
same StoreLock.

Also removes dead cmd_import command and the parse.rs module it depended on.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
Kent Overstreet 2026-04-13 19:03:09 -04:00
parent a1accc7cd4
commit 9309de68fc
5 changed files with 23 additions and 214 deletions

View file

@ -2,7 +2,7 @@
//
// CRUD (upsert, delete), maintenance (decay, cap_degree), and graph metrics.
use super::types::*;
use super::{db, types::*};
use anyhow::{anyhow, bail, Result};
use std::collections::{HashMap, HashSet};
@ -15,7 +15,7 @@ pub fn current_provenance() -> String {
}
impl Store {
/// Add or update a node (appends to log + updates cache).
/// Add or update a node (appends to log + updates cache + redb).
/// Holds StoreLock across refresh + check + write to prevent duplicate UUIDs.
pub fn upsert_node(&mut self, mut node: Node) -> Result<()> {
let _lock = StoreLock::acquire()?;
@ -26,6 +26,9 @@ impl Store {
node.version = existing.version + 1;
}
self.append_nodes_unlocked(&[node.clone()])?;
if let Some(ref database) = self.db {
db::upsert_node(database, &node)?;
}
self.uuid_to_key.insert(node.uuid, node.key.clone());
self.nodes.insert(node.key.clone(), node);
Ok(())
@ -75,19 +78,25 @@ impl Store {
node.timestamp = now_epoch();
node.version += 1;
self.append_nodes_unlocked(std::slice::from_ref(&node))?;
if let Some(ref database) = self.db {
db::upsert_node(database, &node)?;
}
self.nodes.insert(key.to_string(), node);
Ok("updated")
} else {
let mut node = new_node(key, content);
node.provenance = provenance.to_string();
self.append_nodes_unlocked(std::slice::from_ref(&node))?;
if let Some(ref database) = self.db {
db::upsert_node(database, &node)?;
}
self.uuid_to_key.insert(node.uuid, node.key.clone());
self.nodes.insert(key.to_string(), node);
Ok("created")
}
}
/// Soft-delete a node (appends deleted version, removes from cache).
/// Soft-delete a node (appends deleted version, removes from cache + redb).
/// Holds StoreLock across refresh + write to see concurrent creates.
pub fn delete_node(&mut self, key: &str) -> Result<()> {
let _lock = StoreLock::acquire()?;
@ -97,12 +106,16 @@ impl Store {
let node = self.nodes.get(key)
.ok_or_else(|| anyhow!("No node '{}'", key))?;
let uuid = node.uuid;
let mut deleted = node.clone();
deleted.deleted = true;
deleted.version += 1;
deleted.provenance = prov;
deleted.timestamp = now_epoch();
self.append_nodes_unlocked(std::slice::from_ref(&deleted))?;
if let Some(ref database) = self.db {
db::delete_node(database, key, &uuid)?;
}
self.nodes.remove(key);
Ok(())
}
@ -159,11 +172,17 @@ impl Store {
.collect();
// Persist under single lock
self.append_nodes_unlocked(&[renamed.clone(), tombstone])?;
self.append_nodes_unlocked(&[renamed.clone(), tombstone.clone()])?;
if !updated_rels.is_empty() {
self.append_relations_unlocked(&updated_rels)?;
}
// Update redb: delete old key, insert renamed
if let Some(ref database) = self.db {
db::delete_node(database, old_key, &tombstone.uuid)?;
db::upsert_node(database, &renamed)?;
}
// Update in-memory cache
self.nodes.remove(old_key);
self.uuid_to_key.insert(renamed.uuid, new_key.to_string());