use std::sync::Arc;
use std::time::{Duration, Instant};
use macrame::metrics::CommandKind;
use macrame::prelude::*;
const TS: &str = "2026-01-01T00:00:00.000000Z";
const OPEN: &str = "9999-12-31T23:59:59.999999Z";
const IMPORT_EDGES: usize = 900;
const WRITES_PER_WRITER: usize = 20;
async fn seeded(path: &std::path::Path) -> Arc<Database> {
let db = Database::open_with_cadence(path, None).await.unwrap();
let concepts: Vec<_> = (0..=IMPORT_EDGES + 4_000)
.map(|i| ConceptUpsert::new(format!("c{i:06}"), "N").valid_from(TS))
.collect();
db.write_concepts(concepts).await.unwrap();
Arc::new(db)
}
fn import_edges() -> Vec<EdgeAssertion> {
(1..=IMPORT_EDGES)
.map(|i| {
EdgeAssertion::new("c000000", format!("c{i:06}"), "LINKS")
.valid_from(TS)
.valid_to(OPEN)
})
.collect()
}
#[derive(Debug)]
struct Reading {
starved_turns: u64,
run_max: u64,
turns: u64,
import_wall: Duration,
}
fn read(db: &Database, import_wall: Duration) -> Reading {
let s = db.metrics();
Reading {
starved_turns: s.low_starved_turns,
run_max: s.low_starved_run_max,
turns: s.turns,
import_wall,
}
}
async fn closed_loop(path: &std::path::Path, writers: usize, think: Duration) -> Reading {
let db = seeded(path).await;
let importer = {
let db = Arc::clone(&db);
tokio::spawn(async move {
let t = Instant::now();
db.bulk_import(import_edges()).await.unwrap();
t.elapsed()
})
};
let mut hands = Vec::with_capacity(writers);
for w in 0..writers {
let db = Arc::clone(&db);
hands.push(tokio::spawn(async move {
for i in 0..WRITES_PER_WRITER {
db.upsert_concept(
ConceptUpsert::new(format!("w{w:03}_{i:03}"), "W").valid_from(TS),
)
.await
.unwrap();
if !think.is_zero() {
tokio::time::sleep(think).await;
}
}
}));
}
for h in hands {
h.await.unwrap();
}
let import_wall = importer.await.unwrap();
let reading = read(&db, import_wall);
Arc::into_inner(db).unwrap().close().await.unwrap();
reading
}
async fn open_loop(path: &std::path::Path, writers: usize) -> Reading {
let db = seeded(path).await;
let importer = {
let db = Arc::clone(&db);
tokio::spawn(async move {
let t = Instant::now();
db.bulk_import(import_edges()).await.unwrap();
t.elapsed()
})
};
let mut hands = Vec::with_capacity(writers);
for w in 0..writers {
let db = Arc::clone(&db);
hands.push(tokio::spawn(async move {
db.upsert_concept(ConceptUpsert::new(format!("b{w:04}"), "B").valid_from(TS))
.await
.unwrap();
}));
}
for h in hands {
h.await.unwrap();
}
let import_wall = importer.await.unwrap();
let reading = read(&db, import_wall);
Arc::into_inner(db).unwrap().close().await.unwrap();
reading
}
async fn longest_low_holds(path: &std::path::Path) {
let db = seeded(path).await;
db.bulk_import(import_edges()).await.unwrap();
let retire: Vec<EdgeAssertion> = (1..=IMPORT_EDGES)
.map(|i| {
EdgeAssertion::new("c000000", format!("c{i:06}"), "LINKS")
.valid_from(TS)
.valid_to("2026-06-01T00:00:00.000000Z")
})
.collect();
db.bulk_import(retire).await.unwrap();
db.rebuild_current().await.unwrap();
db.archive("2027-01-01T00:00:00.000000Z").await.unwrap();
db.rebuild_fts().await.unwrap();
db.analyze().await.unwrap();
let snap = db.metrics();
for kind in [
CommandKind::Archive,
CommandKind::Analyze,
CommandKind::RebuildFts,
CommandKind::BulkImportChunk,
] {
if let Some(k) = snap.kinds.iter().find(|k| k.kind == kind && k.turns > 0) {
println!(
" {:<20} longest hold {:<12?} budget-exempt: {}",
k.kind.as_str(),
k.longest,
kind.exempt_from_budget()
);
}
}
println!(" (archive on an 8,000-key backlog was measured at 3.3 s unwindowed, D-080.)");
Arc::into_inner(db).unwrap().close().await.unwrap();
}
fn row(label: &str, r: &Reading) {
println!(
" {label:<38} run_max={:<5} starved={:<6} turns={:<6} import={:?}",
r.run_max, r.starved_turns, r.turns, r.import_wall
);
}
#[tokio::main]
async fn main() {
let dir = std::env::temp_dir().join(format!("macrame_fairness_{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let mut n = 0usize;
let mut next = || {
n += 1;
dir.join(format!("f{n}.db"))
};
println!("import = {IMPORT_EDGES} edges, {WRITES_PER_WRITER} writes per writer\n");
println!("===== closed loop: each writer awaits its own write =====");
for writers in [1usize, 2, 4, 8, 16, 64] {
let r = closed_loop(&next(), writers, Duration::ZERO).await;
row(&format!("{writers} writer(s), no think time"), &r);
}
println!("\n===== closed loop, 1 ms between a writer's writes =====");
for writers in [4usize, 16, 64] {
let r = closed_loop(&next(), writers, Duration::from_millis(1)).await;
row(&format!("{writers} writer(s), 1 ms think"), &r);
}
println!("\n===== open loop: D-153's fixture, spawned all at once =====");
for writers in [64usize, 256, 1024] {
let r = open_loop(&next(), writers).await;
row(&format!("{writers} writes fired without waiting"), &r);
}
println!("\n===== what a floor would insert into the interactive path =====");
println!(
" The obvious floor is \"after N starved turns, take one low-priority \
command\". These are the\n low-tier holds that command could be; \
`CHUNK_BUDGET` exempts some of them *by contract*."
);
longest_low_holds(&next()).await;
println!(
"\nRead the run_max column against the writer count, and then against \
the think-time block: the\nrun is bounded by how long the caller keeps \
offering interactive work -- not by concurrency, and not by \
anything in the crate."
);
let _ = std::fs::remove_dir_all(&dir);
}