use std::sync::Arc;
use std::time::Duration;
use logdb::{Config, DurabilityMode, LogDb};
fn main() {
let dir = tempfile::tempdir().unwrap();
let mut config = Config::default();
config.data_dir = dir.path().to_path_buf();
config.shards = 4;
config.ring_size = 256;
config.durability_mode = DurabilityMode::Sync;
config.flush_timeout = Duration::from_secs(5);
let db = Arc::new(LogDb::open(config).unwrap());
let mut handles = Vec::new();
for t in 0..4u64 {
let db = Arc::clone(&db);
handles.push(std::thread::spawn(move || {
(0..10u64)
.map(|i| db.append(format!("t{}-{}", t, i).as_bytes()).unwrap())
.collect::<Vec<u64>>()
}));
}
let mut all_ids = Vec::new();
for h in handles {
all_ids.extend(h.join().unwrap());
}
db.flush().unwrap();
for _ in 0..50 {
if db.scan(0, u64::MAX).unwrap().filter_map(|r| r.ok()).count() >= all_ids.len() {
break;
}
std::thread::sleep(Duration::from_millis(20));
}
println!("wrote {} records across {} shards", all_ids.len(), 4);
let mut sorted = all_ids.clone();
sorted.sort();
sorted.dedup();
assert_eq!(sorted.len(), all_ids.len(), "no duplicate global ids");
let scanned: Vec<u64> = db
.scan(0, u64::MAX)
.unwrap()
.filter_map(|r| r.ok())
.map(|r| r.id.sequence)
.collect();
assert_eq!(scanned.len(), all_ids.len(), "scan must see all shards");
assert!(
scanned.windows(2).all(|w| w[0] < w[1]),
"scan must be ascending"
);
println!("cross-shard scan: {} records ascending — ok", scanned.len());
for &id in &all_ids {
let rec = db.read(id).unwrap().unwrap();
assert_eq!(rec.id.sequence, id);
}
println!("point reads by global id across shards: ok");
let bits = 2u32; for &id in &all_ids {
let (shard, _local) = logdb::decode_record_id(id, bits);
assert!(shard < 4, "shard id must be < num_shards");
}
println!("all global ids decode to valid (shard, local) pairs");
}