#![cfg(loom)]
#![allow(clippy::unwrap_used)]
mod common;
use common::MockIndex;
use iqdb_cache::CachedIndex;
use iqdb_index::IndexCore;
use iqdb_types::{DistanceMetric, SearchParams, VectorId};
use loom::sync::Arc;
#[test]
fn concurrent_searches_of_one_query_are_consistent() {
loom::model(|| {
let mut index = MockIndex::new(2);
index
.insert(
VectorId::from(1u64),
std::sync::Arc::from(&[0.0, 0.0][..]),
None,
)
.unwrap();
let cached = Arc::new(CachedIndex::new(index));
let params = SearchParams::new(1, DistanceMetric::Euclidean);
let threads: Vec<_> = (0..2)
.map(|_| {
let cached = Arc::clone(&cached);
let params = params.clone();
loom::thread::spawn(move || {
let hits = cached.search(&[0.0, 0.0], ¶ms).unwrap();
assert_eq!(hits.len(), 1);
assert_eq!(hits[0].id, VectorId::from(1u64));
})
})
.collect();
for t in threads {
t.join().unwrap();
}
let stats = cached.cache_stats();
assert_eq!(stats.hits + stats.misses, 2);
assert_eq!(stats.len, 1);
});
}
#[test]
fn concurrent_searches_of_distinct_queries_settle() {
loom::model(|| {
let mut index = MockIndex::new(2);
index
.insert(
VectorId::from(1u64),
std::sync::Arc::from(&[0.0, 0.0][..]),
None,
)
.unwrap();
let cached = Arc::new(CachedIndex::new(index));
let params = SearchParams::new(1, DistanceMetric::Euclidean);
let a = {
let cached = Arc::clone(&cached);
let params = params.clone();
loom::thread::spawn(move || {
let _ = cached.search(&[0.0, 0.0], ¶ms).unwrap();
})
};
let b = {
let cached = Arc::clone(&cached);
let params = params.clone();
loom::thread::spawn(move || {
let _ = cached.search(&[1.0, 1.0], ¶ms).unwrap();
})
};
a.join().unwrap();
b.join().unwrap();
let stats = cached.cache_stats();
assert_eq!(stats.misses, 2);
assert_eq!(stats.hits, 0);
assert_eq!(stats.len, 2);
});
}