use criterion::{criterion_group, criterion_main, Criterion};
#[cfg(feature = "write-support")]
use criterion::{black_box, Throughput};
#[path = "fixtures/mod.rs"]
mod fixtures;
#[path = "profiling/mod.rs"]
mod profiling;
#[cfg(feature = "write-support")]
const INGEST_ROWS: u64 = 256;
#[cfg(feature = "write-support")]
const FLUSH_ROWS: u64 = 1_000;
#[cfg(feature = "write-support")]
fn bench_ingest(c: &mut Criterion) {
use rand::Rng;
let mut group = c.benchmark_group("write");
group.throughput(Throughput::Elements(INGEST_ROWS));
group.bench_function("ingest_wal_on", |b| {
b.iter_batched(
|| {
let tmp = tempfile::TempDir::new().expect("create temp dir for ingest bench");
let engine = fixtures::open_write_engine(tmp.path(), usize::MAX);
let rng = fixtures::seeded_rng();
(tmp, engine, rng)
},
|(_tmp, mut engine, mut rng)| {
for _ in 0..INGEST_ROWS {
let id = uuid::Uuid::from_u128(rng.gen());
let age: i32 = rng.gen_range(0..100);
let stmt = format!(
"INSERT INTO test_basic.simple_table \
(id, name, age, active) \
VALUES ({id}, 'bench-row', {age}, true)"
);
engine.execute(&stmt).expect("ingest seeded row");
}
let n = engine.memtable_row_count();
assert!(
n > 0,
"ingest_wal_on: memtable is empty after {INGEST_ROWS} inserts"
);
black_box(n)
},
criterion::BatchSize::SmallInput,
);
});
group.finish();
}
#[cfg(feature = "write-support")]
fn bench_ingest_wal_off(c: &mut Criterion) {
use rand::Rng;
let mut group = c.benchmark_group("write");
group.throughput(Throughput::Elements(INGEST_ROWS));
group.bench_function("ingest_wal_off", |b| {
b.iter_batched(
|| {
let tmp =
tempfile::TempDir::new().expect("create temp dir for ingest_wal_off bench");
let engine = fixtures::open_write_engine_wal_off(tmp.path(), usize::MAX);
let rng = fixtures::seeded_rng();
(tmp, engine, rng)
},
|(_tmp, mut engine, mut rng)| {
for _ in 0..INGEST_ROWS {
let id = uuid::Uuid::from_u128(rng.gen());
let age: i32 = rng.gen_range(0..100);
let stmt = format!(
"INSERT INTO test_basic.simple_table \
(id, name, age, active) \
VALUES ({id}, 'bench-row', {age}, true)"
);
engine.execute(&stmt).expect("ingest seeded row (wal off)");
}
let n = engine.memtable_row_count();
assert!(
n > 0,
"ingest_wal_off: memtable is empty after {INGEST_ROWS} inserts"
);
black_box(n)
},
criterion::BatchSize::SmallInput,
);
});
group.finish();
}
#[cfg(feature = "write-support")]
fn bench_flush(c: &mut Criterion) {
use rand::Rng;
fn fill_engine(engine: &mut cqlite_core::storage::write_engine::WriteEngine) -> usize {
let mut rng = fixtures::seeded_rng();
for _ in 0..FLUSH_ROWS {
let id = uuid::Uuid::from_u128(rng.gen());
let age: i32 = rng.gen_range(0..100);
let salary: i64 = rng.gen_range(30_000..200_000);
let stmt = format!(
"INSERT INTO test_basic.simple_table \
(id, name, age, salary, active) \
VALUES ({id}, 'flush-row', {age}, {salary}, true)"
);
engine.execute(&stmt).expect("fill engine row");
}
engine.memtable_size()
}
let size_probe = {
let tmp = tempfile::TempDir::new().expect("probe temp dir");
let mut engine = fixtures::open_write_engine(tmp.path(), usize::MAX);
let sz = fill_engine(&mut engine);
assert!(
sz > 0,
"flush bench: memtable_size() returned 0 after {FLUSH_ROWS} inserts"
);
sz
};
let rt = tokio::runtime::Runtime::new().expect("tokio runtime for flush bench");
let mut group = c.benchmark_group("write");
group.throughput(Throughput::Bytes(size_probe as u64));
group.bench_function("flush", |b| {
b.iter_batched(
|| {
let tmp = tempfile::TempDir::new().expect("create temp dir for flush bench");
let mut engine = fixtures::open_write_engine(tmp.path(), usize::MAX);
let sz = fill_engine(&mut engine);
assert!(
sz > 0,
"flush bench setup: memtable empty after {FLUSH_ROWS} rows"
);
(tmp, engine)
},
|(_tmp, mut engine)| {
let result = rt.block_on(engine.flush()).expect("flush must not error");
assert!(
result.is_some(),
"flush returned None — nothing was written to disk; \
check that FLUSH_ROWS rows are above the flush threshold"
);
black_box(result)
},
criterion::BatchSize::SmallInput,
);
});
group.finish();
}
#[cfg(feature = "write-support")]
criterion_group!(
name = benches;
config = profiling::configure();
targets = bench_ingest, bench_ingest_wal_off, bench_flush
);
#[cfg(not(feature = "write-support"))]
fn bench_noop(_c: &mut Criterion) {
}
#[cfg(not(feature = "write-support"))]
criterion_group!(
name = benches;
config = profiling::configure();
targets = bench_noop
);
criterion_main!(benches);