use kevy_store::Store;
use crate::index_runtime;
use crate::state::Ctx;
pub(crate) fn classify_prefix_rows(
s: &mut Store,
spec: &kevy_index::IndexSpec,
row_keys: &[Vec<u8>],
indexed: &std::collections::HashSet<&[u8]>,
window: Option<kevy_index::WindowAudit>,
) -> [u64; 5] {
let names = spec.scalar_read_names();
let w = spec.primary_width();
let mut f = [0u64; 5];
let mut below = 0u64;
for key in row_keys {
f[3] += 1;
let cls = match s.peek_hash_fields(key, &names[..w]) {
Ok(Some(vals)) => spec.classify_scalar(&vals),
_ => kevy_index::RowDerivation::Absent,
};
match cls {
kevy_index::RowDerivation::Indexed(_) => {
if !indexed.contains(key.as_slice()) {
if slid_out(s, spec, key, window) {
below += 1;
} else {
f[4] += 1;
}
}
}
kevy_index::RowDerivation::CoerceFailed => f[0] += 1,
kevy_index::RowDerivation::Oversize => f[1] += 1,
kevy_index::RowDerivation::Absent => f[2] += 1,
}
}
f[4] += below.saturating_sub(window.map_or(0, |w| w.cold_live));
f
}
fn slid_out(
s: &mut Store,
spec: &kevy_index::IndexSpec,
key: &[u8],
window: Option<kevy_index::WindowAudit>,
) -> bool {
let Some(w) = window else {
return false;
};
match index_runtime::row_value(s, spec, key) {
index_runtime::RowValue::Value(v) => {
kevy_index::window_value_of(&v, w.shape).is_some_and(|wv| wv < w.boundary)
}
_ => false,
}
}
pub(crate) fn index_verify_counts(
ctx: &Ctx<'_>,
store: &mut Store,
name: &[u8],
) -> Result<[u64; 10], kevy_resp::CmdError> {
let (spec, entries, stats, window) =
index_runtime::with_ready_segment(ctx, store, name, |spec, seg, win| {
let mut entries: Vec<(Vec<u8>, kevy_index::IndexValue)> = Vec::new();
seg.each_entry(|k, v| entries.push((k.to_vec(), v.clone())));
let audit = win.and_then(|w| w.audit(spec.ty));
(spec.clone(), entries, seg.stats(), audit)
})?;
let indexed: std::collections::HashSet<&[u8]> =
entries.iter().map(|(k, _)| k.as_slice()).collect();
let mut pat = spec.prefix.clone();
pat.push(b'*');
let row_keys = store.collect_keys(Some(&pat), None);
let (drift, fresh) = store.peek_scope(|s| {
let mut drift = 0u64;
for (key, held) in &entries {
match index_runtime::row_value(s, &spec, key) {
index_runtime::RowValue::Value(actual) if &actual == held => {}
_ => drift += 1,
}
}
(drift, classify_prefix_rows(s, &spec, &row_keys, &indexed, window))
});
Ok([
stats.entries,
stats.approx_bytes,
fresh[0],
stats.duplicates,
drift,
entries.len() as u64,
fresh[1],
fresh[2],
fresh[3],
fresh[4],
])
}