use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
use std::time::Duration;
use fusedb::{FuseWatcher, FuseWriter};
fn build(path: &std::path::Path, generation: usize) -> Result<(), fusedb::FuseError> {
let mut w = FuseWriter::new();
for i in 0..(generation * 4) {
w.add_raw(format!("key-{i:04}"), format!("v{generation}"))?;
}
w.build(path)?;
Ok(())
}
fn main() -> Result<(), fusedb::FuseError> {
let path = std::env::temp_dir().join("fusedb-watch-example.fsdb");
build(&path, 1)?;
let reloads = Arc::new(AtomicUsize::new(0));
let watcher = {
let reloads = Arc::clone(&reloads);
FuseWatcher::builder(&path)
.interval(Duration::from_millis(100))
.on_reload(move |db| {
let n = reloads.fetch_add(1, Ordering::SeqCst) + 1;
println!(" reload #{n}: now {} keys", db.len());
})
.on_error(|e| eprintln!(" reload failed (still serving old file): {e}"))
.spawn()?
};
println!(
"watching {} — {} keys",
path.display(),
watcher.load().len()
);
println!(" direct read: {:?}", watcher.get_raw("key-0000")?);
let stop = Arc::new(AtomicBool::new(false));
let lookups = Arc::new(AtomicUsize::new(0));
let readers: Vec<_> = (0..4)
.map(|_| {
let reader = Arc::clone(watcher.reader());
let stop = Arc::clone(&stop);
let lookups = Arc::clone(&lookups);
std::thread::spawn(move || {
while !stop.load(Ordering::Relaxed) {
let db = reader.load();
for key in db.keys_raw() {
let _ = db.get_raw(key);
lookups.fetch_add(1, Ordering::Relaxed);
}
}
})
})
.collect();
for generation in 2..=5 {
std::thread::sleep(Duration::from_millis(250));
println!("rebuilding at generation {generation}…");
build(&path, generation)?;
}
std::thread::sleep(Duration::from_millis(300));
stop.store(true, Ordering::Relaxed);
for handle in readers {
handle.join().expect("reader thread panicked");
}
println!(
"done — {} lookups served across {} swaps, no locking on the read path",
lookups.load(Ordering::Relaxed),
watcher.generation(),
);
watcher.stop();
std::fs::remove_file(&path).ok();
Ok(())
}