use btree_store::BTree;
use std::sync::{Arc, Barrier};
use std::thread;
use std::time::{Duration, Instant};
use tempfile::TempDir;
#[test]
fn test_view_isolation_blocks_writer() {
let temp_dir = TempDir::new().unwrap();
let db_path = temp_dir.path().join("isolation.db");
let tree = BTree::open(&db_path).unwrap();
let bucket_name = "iso_bucket";
tree.exec(bucket_name, |txn| {
for i in 0..100 {
txn.put(
format!("key_{:03}", i).as_bytes(),
format!("val_{:03}", i).as_bytes(),
)
.unwrap();
}
Ok(())
})
.unwrap();
let tree_clone_reader = tree.clone();
let tree_clone_writer = tree.clone();
let barrier = Arc::new(Barrier::new(2));
let barrier_clone = barrier.clone();
let reader_handle = thread::spawn(move || {
tree_clone_reader
.view(bucket_name, |txn| {
let _ = txn.get("key_000").unwrap();
barrier_clone.wait();
thread::sleep(Duration::from_millis(500));
let mut count = 0;
let mut iter = txn.iter();
let mut key_buf = Vec::new();
let mut val_buf = Vec::new();
while iter.next_ref(&mut key_buf, &mut val_buf) {
count += 1;
}
Ok(count)
})
.unwrap()
});
let writer_handle = thread::spawn(move || {
barrier.wait();
thread::sleep(Duration::from_millis(10));
let start = Instant::now();
tree_clone_writer
.exec(bucket_name, |txn| {
txn.put(b"new_key", b"new_value").unwrap();
Ok(())
})
.unwrap();
start.elapsed()
});
let reader_count = reader_handle.join().unwrap();
let writer_duration = writer_handle.join().unwrap();
assert_eq!(reader_count, 100, "Reader should see all original items");
assert!(
writer_duration > Duration::from_millis(200),
"Writer should be blocked by Reader's lock. Actual duration: {:?}",
writer_duration
);
tree.view(bucket_name, |txn| {
assert_eq!(txn.get(b"new_key").unwrap(), b"new_value".to_vec());
Ok(())
})
.unwrap();
}