use seerdb::DBOptions;
use std::path::PathBuf;
fn main() {
println!("=== Write Amplification Benchmark ===\n");
const NUM_OPERATIONS: usize = 100_000;
const VALUE_SIZE: usize = 8192; const VLOG_THRESHOLD: usize = 4096;
println!("Benchmark 1: Traditional LSM (no value separation)");
println!("-------------------------------------------------");
let (write_amp_no_vlog, _) = run_benchmark(NUM_OPERATIONS, VALUE_SIZE, None);
println!("Write Amplification: {:.2}x\n", write_amp_no_vlog);
println!(
"Benchmark 2: WiscKey vLog (value separation, threshold={}KB)",
VLOG_THRESHOLD / 1024
);
println!("-------------------------------------------------");
let (write_amp_with_vlog, _) = run_benchmark(NUM_OPERATIONS, VALUE_SIZE, Some(VLOG_THRESHOLD));
println!("Write Amplification: {:.2}x\n", write_amp_with_vlog);
println!("=== Results Summary ===");
println!("Traditional LSM: {:.2}x", write_amp_no_vlog);
println!("WiscKey vLog: {:.2}x", write_amp_with_vlog);
if write_amp_no_vlog > write_amp_with_vlog {
let improvement = write_amp_no_vlog / write_amp_with_vlog;
println!(
"\nImprovement: {:.2}x better with vLog",
improvement
);
println!("Target: 10x better (from paper)");
if improvement >= 5.0 {
println!("Status: ✅ Significant improvement achieved");
} else if improvement >= 2.0 {
println!("Status: ⚠️ Moderate improvement (less than claimed)");
} else {
println!("Status: ❌ Minimal improvement");
}
}
}
fn run_benchmark(num_ops: usize, value_size: usize, vlog_threshold: Option<usize>) -> (f64, u64) {
let temp_dir = format!(
"/tmp/seerdb_writeamp_{}",
vlog_threshold
.map(|t| format!("vlog{}", t))
.unwrap_or_else(|| "novlog".to_string())
);
let path = PathBuf::from(&temp_dir);
let _ = std::fs::remove_dir_all(&path);
let db = DBOptions::default()
.memtable_capacity(4 * 1024 * 1024) .sync_policy(seerdb::SyncPolicy::None) .background_compaction(false) .vlog_threshold(vlog_threshold)
.open(&path)
.expect("Failed to open database");
let value = "x".repeat(value_size);
for i in 0..num_ops {
let key = format!("key_{:08}", i);
db.put(key.as_bytes(), value.as_bytes())
.expect("Put failed");
}
db.flush().expect("Flush failed");
let stats = db.stats();
let logical_bytes = stats.logical_bytes_written;
let physical_bytes = stats.physical_bytes_written;
let write_amp = if logical_bytes > 0 {
physical_bytes as f64 / logical_bytes as f64
} else {
0.0
};
println!(" Operations: {}", num_ops);
println!(" Value size: {} bytes", value_size);
println!(
" Logical bytes: {} MB ({} bytes)",
logical_bytes / 1_000_000,
logical_bytes
);
println!(
" Physical bytes: {} MB ({} bytes)",
physical_bytes / 1_000_000,
physical_bytes
);
println!(" Total SSTables: {}", stats.total_sstables);
println!(" Total flushes: {}", stats.total_flushes);
println!(" Total compactions: {}", stats.total_compactions);
println!(
" Disk usage: {} MB",
stats.total_disk_bytes / 1_000_000
);
drop(db);
let _ = std::fs::remove_dir_all(&path);
(write_amp, physical_bytes)
}