store: remove nodes and uuid_to_key HashMaps

All node access now goes through index → capnp:
- scoring.rs: consolidation_priority, replay_queue, consolidation_plan
- admin.rs: cmd_init, cmd_fsck, cmd_dedup
- engine.rs: run_generator, eval_filter, run_transform
- parser.rs: resolve_field, execute_query

Added Store::remove_from_index() for dedup cleanup.

The relations Vec remains for now (used for graph building).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
Kent Overstreet 2026-04-13 19:49:09 -04:00
parent af3e41f1d9
commit 5877fd857a
5 changed files with 65 additions and 47 deletions

View file

@ -28,13 +28,13 @@ pub async fn cmd_init() -> Result<()> {
// Seed identity node if empty
let arc = memory::access_local()?;
let mut store = arc.lock().await;
if !store.nodes.contains_key("identity") {
if !store.contains_key("identity").unwrap_or(false) {
let default = include_str!("../../defaults/identity.md");
store.upsert("identity", default)?;
println!("Seeded identity in store");
}
store.save()?;
println!("Initialized with {} nodes", store.nodes.len());
println!("Initialized with {} nodes", store.all_keys().unwrap_or_default().len());
// Create config if none exists
let config_path = std::env::var("POC_MEMORY_CONFIG")
@ -65,10 +65,13 @@ pub async fn cmd_fsck() -> Result<()> {
// Check node-key consistency
let mut issues = 0;
for (key, node) in &store.nodes {
if key != &node.key {
eprintln!("MISMATCH: map key '{}' vs node.key '{}'", key, node.key);
issues += 1;
let all_keys = store.all_keys().unwrap_or_default();
for key in &all_keys {
if let Ok(Some(node)) = store.get_node(key) {
if key != &node.key {
eprintln!("MISMATCH: map key '{}' vs node.key '{}'", key, node.key);
issues += 1;
}
}
}
@ -76,11 +79,11 @@ pub async fn cmd_fsck() -> Result<()> {
let mut dangling = 0;
for rel in &store.relations {
if rel.deleted { continue; }
if !store.nodes.contains_key(&rel.source_key) {
if !store.contains_key(&rel.source_key).unwrap_or(false) {
eprintln!("DANGLING: edge source '{}'", rel.source_key);
dangling += 1;
}
if !store.nodes.contains_key(&rel.target_key) {
if !store.contains_key(&rel.target_key).unwrap_or(false) {
eprintln!("DANGLING: edge target '{}'", rel.target_key);
dangling += 1;
}
@ -90,8 +93,8 @@ pub async fn cmd_fsck() -> Result<()> {
let mut to_tombstone = Vec::new();
for rel in &store.relations {
if rel.deleted { continue; }
if !store.nodes.contains_key(&rel.source_key)
|| !store.nodes.contains_key(&rel.target_key) {
if !store.contains_key(&rel.source_key).unwrap_or(false)
|| !store.contains_key(&rel.target_key).unwrap_or(false) {
let mut tombstone = rel.clone();
tombstone.deleted = true;
tombstone.version += 1;
@ -112,7 +115,7 @@ pub async fn cmd_fsck() -> Result<()> {
let g = store.build_graph();
println!("fsck: {} nodes, {} edges, {} issues, {} dangling",
store.nodes.len(), g.edge_count(), issues, dangling);
all_keys.len(), g.edge_count(), issues, dangling);
Ok(())
}
@ -276,8 +279,9 @@ pub async fn cmd_dedup(apply: bool) -> Result<()> {
store.append_relations(&updated_rels)?;
}
for uuid in &doomed_uuids {
store.uuid_to_key.remove(uuid);
// Remove doomed nodes from index
for (doomed_node, _) in &copies[1..] {
store.remove_from_index(&doomed_node.key, &doomed_node.uuid)?;
}
merged += doomed_uuids.len();