use seerdb::{DBOptions, SyncPolicy};
use std::time::Instant;
use tempfile::TempDir;
const NUM_OPERATIONS: usize = 1_000_000; const VALUE_SIZE: usize = 1024;
fn bench_writes(name: &str, background_flush: bool) {
println!("=== {} ===", name);
let temp_dir = TempDir::new().unwrap();
let db = DBOptions::default()
.memtable_capacity(128 * 1024 * 1024) .background_flush(background_flush)
.background_compaction(true)
.sync_policy(SyncPolicy::None)
.vlog_threshold(Some(4096))
.open(temp_dir.path())
.unwrap();
let value = vec![0u8; VALUE_SIZE];
println!("Writing {} operations...", NUM_OPERATIONS);
let start = Instant::now();
for i in 0..NUM_OPERATIONS {
let key = format!("key_{:08}", i);
db.put(key.as_bytes(), &value).unwrap();
if i > 0 && i % 100_000 == 0 {
let elapsed = start.elapsed().as_secs_f64();
let rate = i as f64 / elapsed;
println!(" {:7} ops: {:.0} ops/sec", i, rate);
}
}
db.flush().unwrap();
let elapsed = start.elapsed();
let ops_per_sec = NUM_OPERATIONS as f64 / elapsed.as_secs_f64();
println!("\nResults:");
println!(" Total time: {:.2}s", elapsed.as_secs_f64());
println!(" Throughput: {:.0} ops/sec", ops_per_sec);
println!(
" Latency: {:.2} µs/op",
elapsed.as_micros() as f64 / NUM_OPERATIONS as f64
);
println!();
}
fn bench_mixed(name: &str, background_flush: bool) {
println!("=== {} (Mixed 50/50) ===", name);
let temp_dir = TempDir::new().unwrap();
let db = DBOptions::default()
.memtable_capacity(128 * 1024 * 1024)
.background_flush(background_flush)
.background_compaction(true)
.sync_policy(SyncPolicy::None)
.vlog_threshold(Some(4096))
.open(temp_dir.path())
.unwrap();
let value = vec![0u8; VALUE_SIZE];
println!("Pre-populating with {} entries...", NUM_OPERATIONS);
for i in 0..NUM_OPERATIONS {
let key = format!("key_{:08}", i);
db.put(key.as_bytes(), &value).unwrap();
}
println!("Running mixed workload ({} ops)...", NUM_OPERATIONS);
let start = Instant::now();
for i in 0..NUM_OPERATIONS {
if i % 2 == 0 {
let key = format!("key_{:08}", i);
let _ = db.get(key.as_bytes()).unwrap();
} else {
let key = format!("key_{:08}", i);
db.put(key.as_bytes(), &value).unwrap();
}
if i > 0 && i % 100_000 == 0 {
let elapsed = start.elapsed().as_secs_f64();
let rate = i as f64 / elapsed;
println!(" {:7} ops: {:.0} ops/sec", i, rate);
}
}
let elapsed = start.elapsed();
let ops_per_sec = NUM_OPERATIONS as f64 / elapsed.as_secs_f64();
println!("\nResults:");
println!(" Total time: {:.2}s", elapsed.as_secs_f64());
println!(" Throughput: {:.0} ops/sec", ops_per_sec);
println!(
" Latency: {:.2} µs/op",
elapsed.as_micros() as f64 / NUM_OPERATIONS as f64
);
println!();
}
fn main() {
println!("╔════════════════════════════════════════════════════════════╗");
println!("║ Large Workload Benchmark (1M ops = 1GB) ║");
println!("║ Testing background flush effectiveness ║");
println!("╚════════════════════════════════════════════════════════════╝\n");
bench_writes("Write Workload: Baseline (no background flush)", false);
bench_writes("Write Workload: With background flush", true);
bench_mixed("Mixed Workload: Baseline (no background flush)", false);
bench_mixed("Mixed Workload: With background flush", true);
println!("╔════════════════════════════════════════════════════════════╗");
println!("║ Analysis ║");
println!("╚════════════════════════════════════════════════════════════╝");
println!("If background flush is working correctly:");
println!(" - Writes with background flush should be 10-20%% faster");
println!(" - Mixed with background flush should be 40-60%% faster");
println!("\nReason: Large dataset (1GB) triggers ~8 flushes, eliminating");
println!("flush blocking should significantly improve throughput.");
}