diff --git a/src/cli/admin.rs b/src/cli/admin.rs index de3c987..a9cca43 100644 --- a/src/cli/admin.rs +++ b/src/cli/admin.rs @@ -61,7 +61,7 @@ pub async fn cmd_fsck() -> Result<()> { store::fsck()?; let arc = memory::access_local()?; - let mut store = arc.lock().await; + let store = arc.lock().await; // Check node-key consistency let mut issues = 0; @@ -287,8 +287,9 @@ pub async fn cmd_dedup(apply: bool) -> Result<()> { merged += doomed_uuids.len(); } - // Remove tombstoned relations from cache + // Remove tombstoned relations from cache and rebuild index store.relations.retain(|r| !r.deleted); + store.reindex_relations()?; store.save()?; println!("Merged {} duplicates, redirected {} edges, deduped {} duplicate edges", diff --git a/src/hippocampus/store/index.rs b/src/hippocampus/store/index.rs index 43bbb4f..6615f72 100644 --- a/src/hippocampus/store/index.rs +++ b/src/hippocampus/store/index.rs @@ -209,6 +209,18 @@ pub fn remove_relation( Ok(()) } +/// Clear all relations from the index. +pub fn clear_relations(db: &Database) -> Result<()> { + let txn = db.begin_write()?; + { + // Drop and recreate the table + txn.delete_multimap_table(RELS)?; + let _ = txn.open_multimap_table(RELS)?; + } + txn.commit()?; + Ok(()) +} + /// Get all edges for a node. Returns (other_uuid, strength, rel_type, is_outgoing). pub fn edges_for_node(db: &Database, node_uuid: &[u8; 16]) -> Result> { let txn = db.begin_read()?; diff --git a/src/hippocampus/store/mod.rs b/src/hippocampus/store/mod.rs index c9d57e5..eef031a 100644 --- a/src/hippocampus/store/mod.rs +++ b/src/hippocampus/store/mod.rs @@ -130,6 +130,18 @@ impl Store { Ok(()) } + /// Rebuild relation index from Vec. Call after mutations that modify relations. + pub fn reindex_relations(&self) -> Result<()> { + if let Some(db) = self.db.as_ref() { + index::clear_relations(db)?; + for rel in &self.relations { + if rel.deleted { continue; } + index::index_relation(db, &rel.source, &rel.target, rel.strength, rel.rel_type as u8)?; + } + } + Ok(()) + } + pub fn resolve_key(&self, target: &str) -> Result { // Strip .md suffix if present — keys no longer use it let bare = strip_md_suffix(target);