use std::sync::Arc;
use std::thread;
use std::time::Duration;
use anyhow::Result;
use futures::executor::block_on;
use satoridb::executor::{Executor, WorkerCache};
use satoridb::storage::{Storage, Vector};
use satoridb::wal::runtime::Walrus;
fn init_wal(tmp: &tempfile::TempDir) -> Arc<Walrus> {
Arc::new(Walrus::with_data_dir(tmp.path().to_path_buf()).expect("walrus init"))
}
#[test]
fn executor_handles_concurrent_queries_and_version_bumps() -> Result<()> {
let tmp = tempfile::tempdir()?;
let wal = init_wal(&tmp);
let storage = Storage::new(wal.clone());
let cache = WorkerCache::new(16, 1024 * 1024, 1024 * 1024);
let executor = Arc::new(Executor::new(storage.clone(), cache));
let base_vec = Vector::new(1, vec![0.0, 0.0]);
block_on(storage.put_chunk_raw(0, &[base_vec]))?;
let exec_q = executor.clone();
let query_handle = thread::spawn(move || {
let mut version = 0u64;
for i in 0..20 {
if i == 10 {
version = 1;
}
let res = block_on(exec_q.query(
&[100.0, 100.0],
&[0],
1,
version,
Arc::new(if version == 1 { vec![0] } else { Vec::new() }),
false,
))
.expect("query ok");
assert!(!res.is_empty());
}
});
let storage_writer = storage.clone();
let writer_handle = thread::spawn(move || {
thread::sleep(Duration::from_millis(50));
let closer = Vector::new(2, vec![100.0, 100.0]);
block_on(storage_writer.put_chunk_raw(0, &[closer])).expect("put");
});
writer_handle.join().expect("writer joined");
query_handle.join().expect("query joined");
let res = block_on(executor.query(&[100.0, 100.0], &[0], 1, 2, Arc::new(vec![0]), false))?;
assert_eq!(res[0].0, 2);
Ok(())
}