use ironwal::{Wal, WalOptions};
use std::sync::Arc;
use std::thread;
use tempfile::TempDir;
const STREAM: &str = "test_stream";
fn make_opts(dir: &TempDir, max_entries: u64, max_read_descriptors: usize) -> WalOptions {
let mut opts = WalOptions::new(dir.path());
opts.max_entries_per_segment = max_entries;
opts.max_segment_size = 512; opts.max_open_read_segments = max_read_descriptors;
opts
}
#[test]
fn test_rotated_segment_reads_are_correct() {
let dir = TempDir::new().unwrap();
let opts = make_opts(&dir, 5, 128);
let entries: Vec<Vec<u8>> = (0u64..50).map(|i| format!("entry-{i:04}").into_bytes()).collect();
{
let mut wal = Wal::new(opts.clone()).unwrap();
for (i, e) in entries.iter().enumerate() {
let id = wal.append(STREAM, e).unwrap();
assert_eq!(id, i as u64);
}
}
let wal = Wal::new(opts).unwrap();
for pass in 0..2 {
for (i, expected) in entries.iter().enumerate() {
let val = wal.get(STREAM, i as u64).unwrap();
assert_eq!(
val.as_deref(),
Some(expected.as_slice()),
"pass {pass}: entry {i} mismatch"
);
}
}
}
#[test]
fn test_concurrent_reads_from_rotated_segments() {
let dir = TempDir::new().unwrap();
let opts = make_opts(&dir, 5, 128);
let entries: Vec<Vec<u8>> = (0u64..200).map(|i| format!("value-{i:06}").into_bytes()).collect();
{
let mut wal = Wal::new(opts.clone()).unwrap();
for e in &entries {
wal.append(STREAM, e).unwrap();
}
}
let wal = Arc::new(Wal::new(opts).unwrap());
let entries = Arc::new(entries);
let handles: Vec<_> = (0..8)
.map(|_| {
let wal = Arc::clone(&wal);
let entries = Arc::clone(&entries);
thread::spawn(move || {
for (i, expected) in entries.iter().enumerate() {
let val = wal.get(STREAM, i as u64).unwrap();
assert_eq!(
val.as_deref(),
Some(expected.as_slice()),
"concurrent read: entry {i} mismatch"
);
}
})
})
.collect();
for h in handles {
h.join().expect("reader thread panicked");
}
}
#[test]
fn test_cache_eviction_under_pressure() {
let dir = TempDir::new().unwrap();
let opts = make_opts(&dir, 1, 2);
let entries: Vec<Vec<u8>> = (0u64..20).map(|i| format!("evict-{i:04}").into_bytes()).collect();
{
let mut wal = Wal::new(opts.clone()).unwrap();
for e in &entries {
wal.append(STREAM, e).unwrap();
}
}
let wal = Wal::new(opts).unwrap();
for i in 0..20u64 {
let val = wal.get(STREAM, i).unwrap();
assert_eq!(
val.as_deref(),
Some(entries[i as usize].as_slice()),
"forward read: entry {i}"
);
}
for i in (0..20u64).rev() {
let val = wal.get(STREAM, i).unwrap();
assert_eq!(
val.as_deref(),
Some(entries[i as usize].as_slice()),
"reverse read: entry {i}"
);
}
}