use std::fmt::Write as _;
use std::time::Instant;
use serde_json::json;
use taskfleet_core::{append_and_apply_event, RunPaths};
use tempfile::TempDir;
const TARGET_KEY: &str = "BENCH_TARGET";
const KIND: &str = "bench.probe";
const RUN_ID: &str = "01jxsnap000000000000000000";
fn populate(paths: &RunPaths, n: usize) {
let mut buf = String::with_capacity(n * 128);
for i in 0..n {
let key = if i + 1 == n {
TARGET_KEY.to_string()
} else {
format!("k{i}")
};
let _ = writeln!(
buf,
"{{\"ts\":\"2026-06-12T00:00:00Z\",\"seq\":{seq},\"kind\":\"{KIND}\",\"run_id\":\"{RUN_ID}\",\"idempotency_key\":\"{key}\",\"data\":{{\"status\":\"running\"}}}}",
seq = i + 1,
);
}
std::fs::write(paths.events(), buf).unwrap();
}
fn time_one_scan(paths: &RunPaths) -> f64 {
let t = Instant::now();
let r = append_and_apply_event(
paths,
KIND,
None,
Some(TARGET_KEY),
json!({"status": "running"}),
)
.expect("dedup hit");
let dt = t.elapsed();
assert!(
r.idempotent_replay,
"expected an idempotent replay (full scan)"
);
dt.as_secs_f64() * 1e6
}
fn percentile(sorted: &[f64], p: f64) -> f64 {
if sorted.is_empty() {
return 0.0;
}
let idx = ((p / 100.0) * (sorted.len() as f64 - 1.0)).round() as usize;
sorted[idx]
}
fn bench_n(n: usize, iters: usize) {
let tmp = TempDir::new().unwrap();
let dir = tmp.path().join(RUN_ID);
std::fs::create_dir_all(&dir).unwrap();
let paths = RunPaths::new(dir, RUN_ID).unwrap();
populate(&paths, n);
for _ in 0..5 {
time_one_scan(&paths);
}
let mut samples: Vec<f64> = Vec::with_capacity(iters);
for _ in 0..iters {
samples.push(time_one_scan(&paths));
}
samples.sort_by(|a, b| a.partial_cmp(b).unwrap());
let mean = samples.iter().sum::<f64>() / samples.len() as f64;
let min = samples[0];
let median = percentile(&samples, 50.0);
let p99 = percentile(&samples, 99.0);
let max = *samples.last().unwrap();
println!(
"N={n:>7} iters={iters:>3} min={min:>9.1}µs median={median:>9.1}µs mean={mean:>9.1}µs p99={p99:>9.1}µs max={max:>9.1}µs"
);
}
fn main() {
println!("find_prior_with_key full-scan dedup hit (worst case: key on last line)");
println!("---------------------------------------------------------------------");
bench_n(1_000, 200);
bench_n(10_000, 200);
bench_n(100_000, 100);
}