Add find-deleted diagnostic tool
Lists nodes that are currently deleted with no subsequent live version. Useful for diagnosing accidental deletions in the memory store. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
55326a1c47
commit
465c03aa11
1 changed files with 56 additions and 0 deletions
56
poc-memory/src/bin/find-deleted.rs
Normal file
56
poc-memory/src/bin/find-deleted.rs
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
// Find all deleted nodes that have no subsequent non-deleted version
|
||||||
|
// (i.e., nodes that are currently dead).
|
||||||
|
//
|
||||||
|
// Also checks: is there a live node under the same key with a different UUID?
|
||||||
|
// If not, the deletion was terminal — the node is gone.
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::io::BufReader;
|
||||||
|
use std::fs;
|
||||||
|
use capnp::{message, serialize};
|
||||||
|
use poc_memory::memory_capnp;
|
||||||
|
use poc_memory::store::Node;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let path = std::env::args().nth(1)
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
let dir = poc_memory::store::nodes_path();
|
||||||
|
dir.to_string_lossy().to_string()
|
||||||
|
});
|
||||||
|
|
||||||
|
let file = fs::File::open(&path).unwrap();
|
||||||
|
let mut reader = BufReader::new(file);
|
||||||
|
|
||||||
|
// Collect ALL entries, tracking latest version per key
|
||||||
|
let mut latest_by_key: HashMap<String, Node> = HashMap::new();
|
||||||
|
let mut all_entries = 0u64;
|
||||||
|
|
||||||
|
while let Ok(msg) = serialize::read_message(&mut reader, message::ReaderOptions::new()) {
|
||||||
|
let log = msg.get_root::<memory_capnp::node_log::Reader>().unwrap();
|
||||||
|
for node_reader in log.get_nodes().unwrap() {
|
||||||
|
all_entries += 1;
|
||||||
|
let node = Node::from_capnp_migrate(node_reader).unwrap();
|
||||||
|
let dominated = latest_by_key.get(&node.key)
|
||||||
|
.map(|n| node.version >= n.version)
|
||||||
|
.unwrap_or(true);
|
||||||
|
if dominated {
|
||||||
|
latest_by_key.insert(node.key.clone(), node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find keys where the latest version is deleted
|
||||||
|
let mut dead: Vec<&Node> = latest_by_key.values()
|
||||||
|
.filter(|n| n.deleted)
|
||||||
|
.collect();
|
||||||
|
dead.sort_by(|a, b| a.key.cmp(&b.key));
|
||||||
|
|
||||||
|
eprintln!("Scanned {} entries, {} unique keys", all_entries, latest_by_key.len());
|
||||||
|
eprintln!("{} live nodes, {} deleted (terminal tombstones)\n",
|
||||||
|
latest_by_key.len() - dead.len(), dead.len());
|
||||||
|
|
||||||
|
for node in &dead {
|
||||||
|
println!("{:<60} v{:<4} {}b prov={}",
|
||||||
|
node.key, node.version, node.content.len(), node.provenance);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue