feat: add capnp

Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
2026-02-27 12:15:35 +01:00
parent 3162971c89
commit 749ae245c7
115 changed files with 16596 additions and 31 deletions

View File

@@ -0,0 +1,167 @@
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Instant;
use sq_models::WalConfig;
use sq_sim::SimClock;
use sq_sim::fs::InMemoryFileSystem;
use sq_storage::engine::StorageEngine;
fn bench_write_throughput(payload_size: usize, msg_count: u64) {
let fs = Arc::new(InMemoryFileSystem::new());
let clock = Arc::new(SimClock::new());
let config = WalConfig {
max_segment_bytes: 256 * 1024 * 1024, // 256MB to avoid rotation overhead
max_segment_age_secs: 3600,
data_dir: PathBuf::from("/data"),
..Default::default()
};
let engine = StorageEngine::new(fs, clock, config).unwrap();
let payload = vec![b'x'; payload_size];
let start = Instant::now();
for i in 0..msg_count {
engine.append("bench", 0, None, &payload, &[], i).unwrap();
}
let elapsed = start.elapsed();
let msgs_per_sec = msg_count as f64 / elapsed.as_secs_f64();
let mb_per_sec = (msg_count as f64 * payload_size as f64) / elapsed.as_secs_f64() / 1_048_576.0;
println!(
" write {msg_count} x {payload_size}B: {:.0} msg/s, {:.1} MB/s ({:.2?})",
msgs_per_sec, mb_per_sec, elapsed
);
}
fn bench_read_throughput(payload_size: usize, msg_count: u64) {
let fs = Arc::new(InMemoryFileSystem::new());
let clock = Arc::new(SimClock::new());
let config = WalConfig {
max_segment_bytes: 256 * 1024 * 1024,
max_segment_age_secs: 3600,
data_dir: PathBuf::from("/data"),
..Default::default()
};
let engine = StorageEngine::new(fs, clock, config).unwrap();
let payload = vec![b'x'; payload_size];
for i in 0..msg_count {
engine.append("bench", 0, None, &payload, &[], i).unwrap();
}
let start = Instant::now();
let messages = engine.read("bench", 0, 0, msg_count as usize + 1).unwrap();
let elapsed = start.elapsed();
assert_eq!(messages.len(), msg_count as usize);
let msgs_per_sec = msg_count as f64 / elapsed.as_secs_f64();
let mb_per_sec = (msg_count as f64 * payload_size as f64) / elapsed.as_secs_f64() / 1_048_576.0;
println!(
" read {msg_count} x {payload_size}B: {:.0} msg/s, {:.1} MB/s ({:.2?})",
msgs_per_sec, mb_per_sec, elapsed
);
}
fn bench_compression_ratio(payload_size: usize, msg_count: usize) {
// Build a WAL segment worth of data.
let mut raw_data = Vec::new();
for i in 0..msg_count {
let payload = format!("message-{i}-{}", "x".repeat(payload_size));
raw_data.extend_from_slice(payload.as_bytes());
}
let compressed = zstd::encode_all(raw_data.as_slice(), 3).unwrap();
let ratio = raw_data.len() as f64 / compressed.len() as f64;
println!(
" compress {msg_count} x ~{payload_size}B: {} -> {} ({:.2}x ratio)",
format_bytes(raw_data.len()),
format_bytes(compressed.len()),
ratio
);
// Verify roundtrip.
let decompressed = zstd::decode_all(compressed.as_slice()).unwrap();
assert_eq!(decompressed.len(), raw_data.len());
}
fn bench_recovery(msg_count: u64) {
let fs = Arc::new(InMemoryFileSystem::new());
let clock = Arc::new(SimClock::new());
let config = WalConfig {
max_segment_bytes: 64 * 1024, // Small segments to test multi-segment recovery
max_segment_age_secs: 3600,
data_dir: PathBuf::from("/data"),
..Default::default()
};
// Write messages.
{
let engine = StorageEngine::new(fs.clone(), clock.clone(), config.clone()).unwrap();
for i in 0..msg_count {
engine
.append("bench", 0, None, format!("msg-{i}").as_bytes(), &[], i)
.unwrap();
}
}
// Recover and measure.
let start = Instant::now();
let engine = StorageEngine::new(fs, clock, config).unwrap();
engine.recover().unwrap();
let elapsed = start.elapsed();
let msgs_per_sec = msg_count as f64 / elapsed.as_secs_f64();
println!(
" recover {msg_count} msgs: {:.0} msg/s ({:.2?})",
msgs_per_sec, elapsed
);
// Verify correctness.
let messages = engine.read("bench", 0, 0, msg_count as usize + 1).unwrap();
assert_eq!(messages.len(), msg_count as usize);
}
fn format_bytes(bytes: usize) -> String {
if bytes >= 1_048_576 {
format!("{:.1}MB", bytes as f64 / 1_048_576.0)
} else if bytes >= 1024 {
format!("{:.1}KB", bytes as f64 / 1024.0)
} else {
format!("{bytes}B")
}
}
fn main() {
println!("=== SQ Storage Engine Benchmarks ===\n");
println!("Write throughput:");
bench_write_throughput(64, 100_000);
bench_write_throughput(256, 100_000);
bench_write_throughput(1024, 50_000);
bench_write_throughput(4096, 10_000);
println!("\nRead throughput:");
bench_read_throughput(64, 100_000);
bench_read_throughput(256, 100_000);
bench_read_throughput(1024, 50_000);
bench_read_throughput(4096, 10_000);
println!("\nCompression ratio:");
bench_compression_ratio(64, 10_000);
bench_compression_ratio(256, 10_000);
bench_compression_ratio(1024, 5_000);
bench_compression_ratio(4096, 1_000);
println!("\nRecovery performance:");
bench_recovery(1_000);
bench_recovery(10_000);
bench_recovery(50_000);
println!("\n=== Done ===");
}