#![cfg(feature = "redb")]
use amethystate::store::StoreBackend;
use amethystate::store::builder::{Backend, StoreBuilder};
use amethystate_core::test_utils::TempPath;
const ENTRIES: usize = 5_000;
fn opened_with(path: &TempPath, parallel: bool) -> amethystate::Store {
let store = StoreBuilder::new(path.path())
.backend(Backend::Redb)
.parallel_reads(parallel)
.build()
.unwrap();
assert_eq!(
store.parallel_reads(),
parallel,
"the store was asked for parallel_reads={parallel} and reports otherwise, \
so this test would be comparing one branch with itself"
);
store
}
fn key(i: usize) -> String {
format!("k{i:05}")
}
#[test]
fn both_settings_read_back_the_same_map() {
let path = TempPath::new("parallel_reads");
{
let store = StoreBuilder::new(path.path())
.backend(Backend::Redb)
.build()
.unwrap();
let map = store.kv().map::<String, u64>("wide").unwrap();
for i in 0..ENTRIES {
map.insert(key(i), &(i as u64)).unwrap();
}
store.save_now().unwrap();
}
let sequential = {
let store = opened_with(&path, false);
let map = store.kv().map::<String, u64>("wide").unwrap();
map.entries().collect::<Vec<_>>()
};
let parallel = {
let store = opened_with(&path, true);
let map = store.kv().map::<String, u64>("wide").unwrap();
map.entries().collect::<Vec<_>>()
};
assert_eq!(sequential.len(), ENTRIES, "every entry came back");
assert_eq!(
sequential, parallel,
"dividing the work across cores must not change what is read, nor the \
order it is read in"
);
}
#[test]
fn the_same_bad_entry_is_blamed_either_way() {
let path = TempPath::new("parallel_reads_bad");
{
let store = StoreBuilder::new(path.path())
.backend(Backend::Redb)
.build()
.unwrap();
let map = store.kv().map::<String, u64>("wide").unwrap();
for i in 0..ENTRIES {
map.insert(key(i), &(i as u64)).unwrap();
}
store.save_now().unwrap();
drop(map);
let wide = store.kv().namespace("wide");
wide.set("k01249", &"not a number".to_string()).unwrap();
wide.set("k01251", &"nor is this".to_string()).unwrap();
store.save_now().unwrap();
}
for parallel in [false, true] {
let store = opened_with(&path, parallel);
let failure = store
.kv()
.map::<String, u64>("wide")
.expect_err("a value that will not decode is an error, not an absence");
let text = format!("{failure:?}");
assert!(
text.contains("k01249"),
"parallel = {parallel}: the failure should name the first entry that \
will not decode: {text}"
);
assert!(
!text.contains("k01251"),
"parallel = {parallel}: a later bad entry is not the one to blame: {text}"
);
}
}