use std::io::{self, Write};
use std::path::PathBuf;
use subms::{SubMsPerfHarness, SubMsTimer, summarize, summary_to_json};
use subms_segment_reader::{SegmentReader, SegmentWriter};
const ENTRIES: usize = 50_000;
fn payload(i: usize) -> String {
format!("record-{i}")
}
fn build_base() -> Vec<u8> {
let mut buf = Vec::with_capacity(ENTRIES * 24);
let mut w = SegmentWriter::new(&mut buf);
for i in 0..ENTRIES {
w.write(payload(i).as_bytes()).expect("write");
}
buf
}
fn unique_temp_dir() -> PathBuf {
let mut p = std::env::temp_dir();
let stamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos();
p.push(format!(
"subms-segment-features-{stamp}-{}",
std::process::id()
));
p
}
fn main() -> io::Result<()> {
let mut h = SubMsPerfHarness::new("segment-reader-features", "rust");
h.input("entries", &ENTRIES.to_string());
let base = build_base();
h.add_meta("segment_bytes", &base.len().to_string());
{
let s = h.stage("base_next", ENTRIES);
let mut r = SegmentReader::new(base.as_slice());
for _ in 0..ENTRIES {
let t0 = SubMsTimer::tick();
let _ = r.next_record().expect("read");
s.record(t0.elapsed_ns());
}
}
#[cfg(feature = "mmap")]
{
use std::fs;
use subms_segment_reader::MmapSegmentReader;
let dir = unique_temp_dir();
fs::create_dir_all(&dir)?;
let path = dir.join("segment.bin");
fs::write(&path, &base)?;
let s = h.stage("mmap_next", ENTRIES);
let mut r = MmapSegmentReader::open(&path).expect("mmap open");
for _ in 0..ENTRIES {
let t0 = SubMsTimer::tick();
let _ = r.next_record().expect("read");
s.record(t0.elapsed_ns());
}
drop(r);
fs::remove_file(&path).ok();
fs::remove_dir(&dir).ok();
}
#[cfg(feature = "crc32")]
{
use subms_segment_reader::Crc32SegmentReader;
use subms_segment_reader::features::crc32::Crc32SegmentWriter;
let mut buf = Vec::with_capacity(ENTRIES * 28);
{
let mut w = Crc32SegmentWriter::new(&mut buf);
for i in 0..ENTRIES {
w.write(payload(i).as_bytes()).expect("write");
}
}
let s = h.stage("crc32_next", ENTRIES);
let mut r = Crc32SegmentReader::new(buf.as_slice());
for _ in 0..ENTRIES {
let t0 = SubMsTimer::tick();
let _ = r.next_record().expect("read");
s.record(t0.elapsed_ns());
}
}
#[cfg(feature = "xxh3")]
{
use subms_segment_reader::Xxh3SegmentReader;
use subms_segment_reader::features::xxh3::Xxh3SegmentWriter;
let mut buf = Vec::with_capacity(ENTRIES * 32);
{
let mut w = Xxh3SegmentWriter::new(&mut buf);
for i in 0..ENTRIES {
w.write(payload(i).as_bytes()).expect("write");
}
}
let s = h.stage("xxh3_next", ENTRIES);
let mut r = Xxh3SegmentReader::new(buf.as_slice());
for _ in 0..ENTRIES {
let t0 = SubMsTimer::tick();
let _ = r.next_record().expect("read");
s.record(t0.elapsed_ns());
}
}
#[cfg(feature = "lz4")]
{
use subms_segment_reader::{Lz4BlockWriter, Lz4SegmentReader};
let mut buf = Vec::with_capacity(ENTRIES * 16);
{
let mut w = Lz4BlockWriter::new(&mut buf);
for i in 0..ENTRIES {
let body = format!("record-{i}-{}", "ab".repeat(24));
w.write(body.as_bytes()).expect("write");
}
}
let s = h.stage("lz4_next", ENTRIES);
let mut r = Lz4SegmentReader::new(buf.as_slice());
for _ in 0..ENTRIES {
let t0 = SubMsTimer::tick();
let _ = r.next_record().expect("read");
s.record(t0.elapsed_ns());
}
}
#[cfg(feature = "seek-index")]
{
use subms_segment_reader::IndexedSegmentReader;
let mut r = IndexedSegmentReader::open(base.as_slice()).expect("index open");
let total = r.total_blocks();
let mut state: u64 = 0x9e3779b97f4a7c15;
let mut next_target = || {
state = state
.wrapping_mul(6364136223846793005)
.wrapping_add(1442695040888963407);
(state >> 33) as u32 % total
};
let seek_targets: Vec<u32> = (0..ENTRIES).map(|_| next_target()).collect();
{
let s = h.stage("seek", ENTRIES);
for &target in &seek_targets {
let t0 = SubMsTimer::tick();
r.seek_to_block(target).expect("seek");
s.record(t0.elapsed_ns());
}
}
{
let s = h.stage("next_after_seek", ENTRIES);
for &target in &seek_targets {
r.seek_to_block(target).expect("seek");
let t0 = SubMsTimer::tick();
let _ = r.next_record().expect("read");
s.record(t0.elapsed_ns());
}
}
}
#[cfg(feature = "wal-cursor")]
{
use subms_segment_reader::WalCursorReader;
let s = h.stage("read_committed", ENTRIES);
let mut r = WalCursorReader::with_committed(base.as_slice(), base.len());
for _ in 0..ENTRIES {
let t0 = SubMsTimer::tick();
let _ = r.read_committed().expect("read");
s.record(t0.elapsed_ns());
}
}
let summary = summarize(&h);
let mut stdout = io::stdout();
summary_to_json(&summary, &mut stdout)?;
writeln!(stdout)?;
Ok(())
}