use crate::translator::Translator;
use commonware_runtime::Metrics;
mod storage;
pub mod ordered;
pub mod partitioned;
pub mod unordered;
pub trait Cursor: Send + Sync {
type Value: Send + Sync;
#[allow(clippy::should_implement_trait)]
fn next(&mut self) -> Option<&Self::Value>;
fn insert(&mut self, value: Self::Value);
fn delete(&mut self);
fn update(&mut self, value: Self::Value);
fn retain(&mut self, should_retain: &impl Fn(&Self::Value) -> bool) {
while let Some(old) = self.next() {
if !should_retain(old) {
self.delete();
}
}
}
fn find(&mut self, predicate: impl Fn(&Self::Value) -> bool) -> bool {
loop {
match self.next() {
Some(value) if predicate(value) => return true,
Some(_) => continue,
None => return false,
}
}
}
}
pub trait Unordered: Send + Sync {
type Value: Send + Sync;
type Cursor<'a>: Cursor<Value = Self::Value>
where
Self: 'a;
fn get<'a>(&'a self, key: &[u8]) -> impl Iterator<Item = &'a Self::Value> + Send + 'a
where
Self::Value: 'a;
fn get_many<'a, K: AsRef<[u8]>>(
&'a self,
keys: &[K],
mut visit: impl FnMut(usize, &'a Self::Value),
) where
Self::Value: 'a,
{
for (key_idx, key) in keys.iter().enumerate() {
for value in self.get(key.as_ref()) {
visit(key_idx, value);
}
}
}
fn get_mut<'a>(&'a mut self, key: &[u8]) -> Option<Self::Cursor<'a>>;
fn get_mut_or_insert<'a>(
&'a mut self,
key: &[u8],
value: Self::Value,
) -> Option<Self::Cursor<'a>>;
fn insert(&mut self, key: &[u8], value: Self::Value);
fn insert_and_retain(
&mut self,
key: &[u8],
value: Self::Value,
should_retain: impl Fn(&Self::Value) -> bool,
);
fn retain(&mut self, key: &[u8], should_retain: impl Fn(&Self::Value) -> bool) {
if let Some(mut cursor) = self.get_mut(key) {
cursor.retain(&should_retain);
}
}
fn remove(&mut self, key: &[u8]);
#[cfg(test)]
fn keys(&self) -> usize;
#[cfg(test)]
fn items(&self) -> usize;
#[cfg(test)]
fn pruned(&self) -> usize;
}
pub trait Factory<T: Translator>: Unordered + Sized {
fn new(ctx: impl Metrics, translator: T) -> Self;
}
pub trait Ordered: Unordered + Send + Sync {
fn prev_translated_key<'a>(
&'a self,
key: &[u8],
) -> Option<(impl Iterator<Item = &'a Self::Value> + Send + 'a, bool)>
where
Self::Value: 'a;
fn next_translated_key<'a>(
&'a self,
key: &[u8],
) -> Option<(impl Iterator<Item = &'a Self::Value> + Send + 'a, bool)>
where
Self::Value: 'a;
fn first_translated_key<'a>(
&'a self,
) -> Option<impl Iterator<Item = &'a Self::Value> + Send + 'a>
where
Self::Value: 'a;
fn last_translated_key<'a>(
&'a self,
) -> Option<impl Iterator<Item = &'a Self::Value> + Send + 'a>
where
Self::Value: 'a;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
index::partitioned::{
ordered::Index as PartitionedOrdered, unordered::Index as PartitionedUnordered,
},
translator::{EightCap, OneCap, TwoCap},
};
use commonware_macros::test_traced;
use commonware_runtime::{deterministic, Runner, Supervisor as _};
use commonware_utils::sync::Mutex;
use rand::RngExt as _;
use std::{
collections::{HashMap, HashSet},
sync::Arc,
thread,
};
fn values<I: Unordered<Value = u64>>(index: &I, key: &[u8]) -> Vec<u64> {
index.get(key).copied().collect()
}
fn assert_values<I: Unordered<Value = u64>>(index: &I, key: &[u8], expected: &[u64]) {
let mut actual = values(index, key);
actual.sort_unstable();
let mut expected = expected.to_vec();
expected.sort_unstable();
assert_eq!(actual, expected);
}
fn run_index_basic<I: Unordered<Value = u64>>(index: &mut I) {
let key = b"duplicate".as_slice();
index.insert(key, 1);
index.insert(key, 2);
index.insert(key, 3);
assert_eq!(index.keys(), 1);
assert_values(index, key, &[1, 2, 3]);
{
let mut cursor = index.get_mut(key).unwrap();
let mut seen = Vec::new();
while let Some(value) = cursor.next() {
seen.push(*value);
}
seen.sort_unstable();
assert_eq!(seen, vec![1, 2, 3]);
assert!(cursor.next().is_none());
}
index.insert(key, 3);
index.insert(key, 4);
index.retain(key, |i| *i != 3);
assert_values(index, key, &[1, 2, 4]);
index.retain(key, |_| false);
assert_eq!(
index.get(key).copied().collect::<Vec<_>>(),
Vec::<u64>::new()
);
assert_eq!(index.keys(), 0);
assert!(index.get_mut(key).is_none());
index.retain(key, |_| false);
}
fn new_unordered(context: deterministic::Context) -> unordered::Index<TwoCap, u64> {
unordered::Index::new(context, TwoCap)
}
fn new_ordered(context: deterministic::Context) -> ordered::Index<TwoCap, u64> {
ordered::Index::new(context, TwoCap)
}
fn new_partitioned_unordered(
context: deterministic::Context,
) -> PartitionedUnordered<OneCap, u64, 1> {
PartitionedUnordered::new(context, OneCap)
}
fn new_partitioned_ordered(
context: deterministic::Context,
) -> PartitionedOrdered<OneCap, u64, 1> {
PartitionedOrdered::new(context, OneCap)
}
fn new_partitioned_ordered_spilling(
context: deterministic::Context,
) -> PartitionedOrdered<OneCap, u64, 1> {
PartitionedOrdered::with_threshold(context, OneCap, 2)
}
#[test_traced]
fn test_partitioned_ordered_spilling() {
let runner = deterministic::Runner::default();
runner.start(|mut context| async move {
macro_rules! spilled {
($($h:ident),+ $(,)?) => {$(
$h(&mut new_partitioned_ordered_spilling(
context.child(concat!("spill_", stringify!($h))),
));
)+};
}
spilled!(
run_index_basic,
run_index_get_many,
run_index_cursor_find,
run_index_key_lengths_and_metrics,
run_index_values,
run_index_remove_specific,
run_index_empty_key,
run_index_mutate_through_iterator,
run_index_mutate_middle_of_four,
run_index_remove_through_iterator,
run_index_insert_through_iterator,
run_index_cursor_insert_after_done_appends,
run_index_remove_to_nothing_then_add,
run_index_insert_and_remove_cursor,
run_index_insert_and_retain_vacant,
run_index_insert_and_retain_vacant_not_retained,
run_index_insert_and_retain_replace_one,
run_index_insert_and_retain_dead_insert,
run_index_insert_and_retain_single_value,
run_index_remove_middle_then_next,
run_index_remove_to_nothing,
run_index_cursor_insert_with_next,
run_index_cursor_delete_last_then_next,
run_index_delete_in_middle_then_continue,
run_index_delete_first,
run_index_delete_first_and_insert,
run_index_insert_at_entry_then_next,
run_index_delete_last_then_insert_while_done,
run_index_drop_mid_iteration_preserves_chain,
run_index_entry_replacement_not_a_collision,
run_index_large_collision_chain,
);
let mut index = new_partitioned_ordered_spilling(context.child("spill_many_keys"));
run_index_many_keys(&mut index, |bytes| context.fill(bytes));
assert!(
index.spilled_count() > 0,
"routing battery should exercise the spilled representation"
);
});
}
fn run_ordered_short_keys<I: Ordered<Value = u64>>(index: &mut I) {
let keys: [&[u8]; 5] = [
&[0x00, 0x05],
&[0x01],
&[0x02, 0x09, 0xAB],
&[0x03],
&[0xFF, 0xFF],
];
for (rank, &key) in keys.iter().enumerate() {
index.insert(key, rank as u64);
}
let first: Vec<u64> = index.first_translated_key().unwrap().copied().collect();
let last: Vec<u64> = index.last_translated_key().unwrap().copied().collect();
assert_eq!(first, vec![0], "first key");
assert_eq!(last, vec![4], "last key");
let n = keys.len() as u64;
for (i, &key) in keys.iter().enumerate() {
let i = i as u64;
let (it, next_cycled) = index.next_translated_key(key).unwrap();
let next: Vec<u64> = it.copied().collect();
let (it, prev_cycled) = index.prev_translated_key(key).unwrap();
let prev: Vec<u64> = it.copied().collect();
if i + 1 < n {
assert_eq!(
(next, next_cycled),
(vec![i + 1], false),
"next of rank {i}"
);
} else {
assert_eq!((next, next_cycled), (vec![0], true), "next wraps past last");
}
if i > 0 {
assert_eq!(
(prev, prev_cycled),
(vec![i - 1], false),
"prev of rank {i}"
);
} else {
assert_eq!(
(prev, prev_cycled),
(vec![n - 1], true),
"prev wraps before first"
);
}
}
}
#[test_traced]
fn test_ordered_short_keys_flat() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = ordered::Index::<EightCap, u64>::new(context, EightCap);
run_ordered_short_keys(&mut index);
});
}
#[test_traced]
fn test_ordered_short_keys_partitioned() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = PartitionedOrdered::<EightCap, u64, 2>::new(context, EightCap);
run_ordered_short_keys(&mut index);
});
}
#[test_traced]
fn test_hash_index_basic() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
assert_eq!(index.keys(), 0);
run_index_basic(&mut index);
assert_eq!(index.keys(), 0);
});
}
#[test_traced]
fn test_ordered_index_basic() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
assert_eq!(index.keys(), 0);
run_index_basic(&mut index);
assert_eq!(index.keys(), 0);
});
}
#[test_traced]
fn test_partitioned_index_basic() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
assert_eq!(index.keys(), 0);
run_index_basic(&mut index);
assert_eq!(index.keys(), 0);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
assert_eq!(index.keys(), 0);
run_index_basic(&mut index);
assert_eq!(index.keys(), 0);
}
});
}
fn run_index_get_many<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"ab", 1);
index.insert(b"ab", 2);
index.insert(b"abX", 3);
index.insert(b"zz", 4);
let keys: Vec<&[u8]> = vec![b"zz", b"missing", b"ab", b"zz"];
let mut visits: Vec<Vec<u64>> = vec![Vec::new(); keys.len()];
index.get_many(&keys, |key_idx, value| visits[key_idx].push(*value));
visits[2].sort_unstable();
assert_eq!(visits[0], vec![4]);
assert!(visits[1].is_empty());
assert_eq!(visits[2], vec![1, 2, 3]);
assert_eq!(visits[3], vec![4]);
index.get_many::<&[u8]>(&[], |_, _| panic!("no visits expected"));
}
#[test_traced]
fn test_hash_index_get_many() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_get_many(&mut index);
});
}
#[test_traced]
fn test_ordered_index_get_many() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_get_many(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_get_many() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_get_many(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_get_many(&mut index);
}
});
}
fn run_index_cursor_find<I: Unordered<Value = u64>>(index: &mut I) {
let key = b"test_key";
index.insert(key, 10);
index.insert(key, 20);
index.insert(key, 30);
index.insert(key, 40);
{
let mut cursor = index.get_mut(key).unwrap();
assert!(cursor.find(|&v| v == 30));
cursor.update(35);
}
let values: Vec<u64> = index.get(key).copied().collect();
assert!(values.contains(&35));
assert!(!values.contains(&30));
{
let mut cursor = index.get_mut(key).unwrap();
assert!(!cursor.find(|&v| v == 100));
assert!(cursor.next().is_none());
}
{
let mut cursor = index.get_mut(key).unwrap();
assert!(cursor.find(|&v| v == 20));
cursor.delete();
}
let values: Vec<u64> = index.get(key).copied().collect();
assert!(!values.contains(&20));
assert_eq!(values.len(), 3); }
#[test_traced]
fn test_unordered_index_cursor_find() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_cursor_find(&mut index);
});
}
#[test_traced]
fn test_ordered_index_cursor_find() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_cursor_find(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_cursor_find() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_cursor_find(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_cursor_find(&mut index);
}
});
}
fn run_index_many_keys<I: Unordered<Value = u64>>(
index: &mut I,
mut fill: impl FnMut(&mut [u8]),
) {
let mut expected = HashMap::new();
let mut translated = HashSet::new();
cfg_if::cfg_if! {
if #[cfg(miri)] {
const NUM_KEYS: usize = 200;
} else {
const NUM_KEYS: usize = 2000;
}
}
while expected.len() < NUM_KEYS {
let mut key_array = [0u8; 32];
fill(&mut key_array);
translated.insert([key_array[0], key_array[1]]);
let key = key_array.to_vec();
let loc = expected.len() as u64;
index.insert(&key, loc);
expected.insert(key, loc);
}
assert_eq!(index.keys(), translated.len());
assert_eq!(index.items(), NUM_KEYS);
for (key, loc) in expected.iter() {
let mut values = index.get(key);
let res = values.find(|i| *i == loc);
assert!(res.is_some());
}
}
#[test_traced]
fn test_hash_index_many_keys() {
let runner = deterministic::Runner::default();
runner.start(|mut context| async move {
let mut index = new_unordered(context.child("storage"));
run_index_many_keys(&mut index, |bytes| context.fill(bytes));
});
}
#[test_traced]
fn test_ordered_index_many_keys() {
let runner = deterministic::Runner::default();
runner.start(|mut context| async move {
let mut index = new_ordered(context.child("storage"));
run_index_many_keys(&mut index, |bytes| context.fill(bytes));
});
}
#[test_traced]
fn test_partitioned_index_many_keys() {
let runner = deterministic::Runner::default();
runner.start(|mut context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_many_keys(&mut index, |bytes| context.fill(bytes));
}
});
let runner = deterministic::Runner::default();
runner.start(|mut context| async move {
let mut index = new_partitioned_ordered(context.child("storage"));
run_index_many_keys(&mut index, |bytes| context.fill(bytes));
});
}
fn run_index_key_lengths_and_metrics<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"a", 1);
index.insert(b"ab", 2);
index.insert(b"abc", 3);
assert_values(index, b"ab", &[2, 3]);
assert_values(index, b"abc", &[2, 3]);
index.insert(b"ab", 4);
assert_values(index, b"ab", &[2, 3, 4]);
assert_eq!(index.keys(), 2);
assert_eq!(index.items(), 4);
index.retain(b"ab", |v| *v != 4);
assert_values(index, b"ab", &[2, 3]);
assert_eq!(index.keys(), 2);
assert_eq!(index.items(), 3);
index.retain(b"ab", |_| false);
assert_eq!(
index.get(b"ab").copied().collect::<Vec<_>>(),
Vec::<u64>::new()
);
assert_eq!(index.keys(), 1);
assert_eq!(index.items(), 1);
assert_values(index, b"a", &[1]);
}
#[test_traced]
fn test_hash_index_key_lengths_and_key_item_metrics() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_key_lengths_and_metrics(&mut index);
});
}
#[test_traced]
fn test_ordered_index_key_lengths_and_key_item_metrics() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_key_lengths_and_metrics(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_key_lengths_and_key_item_metrics() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_key_lengths_and_metrics(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_key_lengths_and_metrics(&mut index);
}
});
}
fn run_index_values<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"key", 1);
index.insert(b"key", 2);
index.insert(b"key", 3);
assert_values(index, b"key", &[1, 2, 3]);
}
#[test_traced]
fn test_hash_index_values() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_values(&mut index);
});
}
#[test_traced]
fn test_ordered_index_values() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_values(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_values() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_values(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_values(&mut index);
}
});
}
fn run_index_remove_specific<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"key", 1);
index.insert(b"key", 2);
index.insert(b"key", 3);
index.retain(b"key", |v| *v != 2);
assert_values(index, b"key", &[1, 3]);
index.retain(b"key", |v| *v != 1);
assert_values(index, b"key", &[3]);
}
#[test_traced]
fn test_hash_index_remove_specific() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_remove_specific(&mut index);
});
}
#[test_traced]
fn test_ordered_index_remove_specific() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_remove_specific(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_remove_specific() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_remove_specific(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_remove_specific(&mut index);
}
});
}
fn run_index_empty_key<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"", 0);
index.insert(b"\0", 1);
index.insert(b"\0\0", 2);
let mut values = index.get(b"").copied().collect::<Vec<_>>();
values.sort();
assert_eq!(values, vec![0, 1, 2]);
let mut values = index.get(b"\0").copied().collect::<Vec<_>>();
values.sort();
assert_eq!(values, vec![0, 1, 2]);
let mut values = index.get(b"\0\0").copied().collect::<Vec<_>>();
values.sort();
assert_eq!(values, vec![0, 1, 2]);
index.retain(b"", |v| *v != 1);
let mut values = index.get(b"").copied().collect::<Vec<_>>();
values.sort();
assert_eq!(values, vec![0, 2]);
}
#[test_traced]
fn test_hash_index_empty_key() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_empty_key(&mut index);
});
}
#[test_traced]
fn test_ordered_index_empty_key() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_empty_key(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_empty_key() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_empty_key(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_empty_key(&mut index);
}
});
}
fn run_index_mutate_through_iterator<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"key", 1);
index.insert(b"key", 2);
index.insert(b"key", 3);
{
let mut cursor = index.get_mut(b"key").unwrap();
while let Some(old) = cursor.next().copied() {
cursor.update(old + 10);
}
}
assert_values(index, b"key", &[11, 12, 13]);
}
#[test_traced]
fn test_hash_index_mutate_through_iterator() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_mutate_through_iterator(&mut index);
});
}
#[test_traced]
fn test_ordered_index_mutate_through_index() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_mutate_through_iterator(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_mutate_through_iterator() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_mutate_through_iterator(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_mutate_through_iterator(&mut index);
}
});
}
fn run_index_mutate_middle_of_four<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"key", 1);
index.insert(b"key", 2);
index.insert(b"key", 3);
index.insert(b"key", 4);
let mut expected = values(index, b"key");
{
let mut cursor = index.get_mut(b"key").unwrap();
assert_eq!(*cursor.next().unwrap(), expected[0]);
assert_eq!(*cursor.next().unwrap(), expected[1]);
let _ = cursor.next().unwrap();
cursor.update(99);
}
expected[2] = 99;
assert_eq!(values(index, b"key"), expected);
}
#[test_traced]
fn test_hash_index_mutate_middle_of_four() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_mutate_middle_of_four(&mut index);
});
}
#[test_traced]
fn test_ordered_index_mutate_middle_of_four() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_mutate_middle_of_four(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_mutate_middle_of_four() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_mutate_middle_of_four(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_mutate_middle_of_four(&mut index);
}
});
}
fn run_index_remove_through_iterator<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"key", 10);
index.insert(b"key", 20);
index.insert(b"key", 30);
index.insert(b"key", 40);
let mut expected = values(index, b"key");
assert_values(index, b"key", &[10, 20, 30, 40]);
assert_eq!(index.pruned(), 0);
{
let mut cursor = index.get_mut(b"key").unwrap();
assert_eq!(*cursor.next().unwrap(), expected[0]);
cursor.delete();
}
expected.remove(0);
assert_eq!(index.pruned(), 1);
assert_eq!(values(index, b"key"), expected);
index.insert(b"key", 50);
expected.push(50);
assert_values(index, b"key", &expected);
expected = values(index, b"key");
{
let mut cursor = index.get_mut(b"key").unwrap();
assert_eq!(*cursor.next().unwrap(), expected[0]);
assert_eq!(*cursor.next().unwrap(), expected[1]);
assert_eq!(*cursor.next().unwrap(), expected[2]);
cursor.delete();
}
expected.remove(2);
assert_eq!(index.pruned(), 2);
assert_eq!(values(index, b"key"), expected);
index.insert(b"key", 60);
expected.push(60);
assert_values(index, b"key", &expected);
expected = values(index, b"key");
{
let mut cursor = index.get_mut(b"key").unwrap();
for value in &expected {
assert_eq!(*cursor.next().unwrap(), *value);
}
cursor.delete();
}
expected.pop();
assert_eq!(index.pruned(), 3);
assert_eq!(values(index, b"key"), expected);
index.remove(b"key");
assert_eq!(index.keys(), 0);
assert_eq!(index.items(), 0);
assert_eq!(index.pruned(), 6);
}
#[test_traced]
fn test_hash_index_remove_through_iterator() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_remove_through_iterator(&mut index);
});
}
#[test_traced]
fn test_ordered_index_remove_through_iterator() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_remove_through_iterator(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_remove_through_iterator() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_remove_through_iterator(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_remove_through_iterator(&mut index);
}
});
}
fn run_index_insert_through_iterator<I: Unordered<Value = u64>>(index: &mut I)
where
I::Value: PartialEq<u64> + Eq,
{
index.insert(b"key", 1);
{
let mut cursor = index.get_mut(b"key").unwrap();
assert_eq!(*cursor.next().unwrap(), 1);
cursor.insert(3);
}
assert_eq!(index.get(b"key").copied().collect::<Vec<_>>(), vec![1, 3]);
assert_eq!(index.keys(), 1);
assert_eq!(index.items(), 2);
{
let mut cursor = index.get_mut(b"key").unwrap();
assert_eq!(*cursor.next().unwrap(), 1);
cursor.insert(42);
}
assert_eq!(index.keys(), 1);
assert_eq!(index.items(), 3);
{
let mut iter = index.get(b"key");
assert_eq!(*iter.next().unwrap(), 1);
assert_eq!(*iter.next().unwrap(), 42);
}
index.insert(b"key", 100);
assert_values(index, b"key", &[1, 3, 42, 100]);
}
#[test_traced]
fn test_hash_index_insert_through_iterator() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_insert_through_iterator(&mut index);
});
}
#[test_traced]
fn test_ordered_index_insert_through_iterator() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_insert_through_iterator(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_insert_through_iterator() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_insert_through_iterator(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_insert_through_iterator(&mut index);
}
});
}
fn run_index_cursor_insert_after_done_appends<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"key", 10);
{
let mut cursor = index.get_mut(b"key").unwrap();
assert_eq!(*cursor.next().unwrap(), 10);
assert!(cursor.next().is_none());
cursor.insert(20);
}
assert_eq!(index.get(b"key").copied().collect::<Vec<_>>(), vec![10, 20]);
}
#[test_traced]
fn test_hash_index_cursor_insert_after_done_appends() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_cursor_insert_after_done_appends(&mut index);
});
}
#[test_traced]
fn test_ordered_index_cursor_insert_after_done_appends() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_cursor_insert_after_done_appends(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_cursor_insert_after_done_appends() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_cursor_insert_after_done_appends(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_cursor_insert_after_done_appends(&mut index);
}
});
}
fn run_index_remove_to_nothing_then_add<I: Unordered<Value = u64>>(index: &mut I) {
for i in 0..4 {
index.insert(b"key", i);
}
{
let mut cursor = index.get_mut(b"key").unwrap();
let mut removed = Vec::new();
while let Some(value) = cursor.next().copied() {
removed.push(value);
cursor.delete();
}
removed.sort_unstable();
assert_eq!(removed, vec![0, 1, 2, 3]);
assert_eq!(cursor.next(), None);
cursor.insert(4);
assert_eq!(cursor.next(), None);
cursor.insert(5);
}
assert_eq!(index.get(b"key").copied().collect::<Vec<_>>(), vec![4, 5]);
}
#[test_traced]
fn test_hash_index_remove_to_nothing_then_add() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_remove_to_nothing_then_add(&mut index);
});
}
#[test_traced]
fn test_ordered_index_remove_to_nothing_then_add() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_remove_to_nothing_then_add(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_remove_to_nothing_then_add() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_remove_to_nothing_then_add(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_remove_to_nothing_then_add(&mut index);
}
});
}
fn run_index_insert_and_remove_cursor<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"key", 0);
{
let mut cursor = index.get_mut(b"key").unwrap();
assert_eq!(*cursor.next().unwrap(), 0);
cursor.delete();
}
index.remove(b"key");
assert!(index.get(b"key").copied().collect::<Vec<_>>().is_empty());
}
#[test_traced]
fn test_hash_index_insert_and_remove_cursor() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_insert_and_remove_cursor(&mut index);
});
}
#[test_traced]
fn test_ordered_index_insert_and_remove_cursor() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_insert_and_remove_cursor(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_insert_and_remove_cursor() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_insert_and_remove_cursor(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_insert_and_remove_cursor(&mut index);
}
});
}
fn run_index_insert_and_retain_vacant<I: Unordered<Value = u64>>(index: &mut I) {
index.insert_and_retain(b"key", 1u64, |_| true);
assert_eq!(index.get(b"key").copied().collect::<Vec<_>>(), vec![1]);
assert_eq!(index.items(), 1);
assert_eq!(index.keys(), 1);
assert_eq!(index.pruned(), 0);
}
#[test_traced]
fn test_hash_index_insert_and_retain_vacant() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_insert_and_retain_vacant(&mut index);
});
}
#[test_traced]
fn test_ordered_index_insert_and_retain_vacant() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_insert_and_retain_vacant(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_insert_and_retain_vacant() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_insert_and_retain_vacant(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_insert_and_retain_vacant(&mut index);
}
});
}
fn run_index_insert_and_retain_vacant_not_retained<I: Unordered<Value = u64>>(index: &mut I) {
index.insert_and_retain(b"key", 1u64, |_| false);
assert_eq!(
index.get(b"key").copied().collect::<Vec<_>>(),
Vec::<u64>::new()
);
assert_eq!(index.items(), 0);
assert_eq!(index.keys(), 0);
assert_eq!(index.pruned(), 0);
}
#[test_traced]
fn test_hash_index_insert_and_retain_vacant_not_retained() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_insert_and_retain_vacant_not_retained(&mut index);
});
}
#[test_traced]
fn test_ordered_index_insert_and_retain_vacant_not_retained() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_insert_and_retain_vacant_not_retained(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_insert_and_retain_vacant_not_retained() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_insert_and_retain_vacant_not_retained(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_insert_and_retain_vacant_not_retained(&mut index);
}
});
}
fn run_index_insert_and_retain_replace_one<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"key", 1u64);
index.insert_and_retain(b"key", 2u64, |v| *v != 1);
assert_eq!(index.get(b"key").copied().collect::<Vec<_>>(), vec![2]);
assert_eq!(index.items(), 1);
assert_eq!(index.keys(), 1);
assert_eq!(index.pruned(), 1);
}
#[test_traced]
fn test_hash_index_insert_and_retain_replace_one() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_insert_and_retain_replace_one(&mut index);
});
}
#[test_traced]
fn test_ordered_index_insert_and_retain_replace_one() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_insert_and_retain_replace_one(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_insert_and_retain_replace_one() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_insert_and_retain_replace_one(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_insert_and_retain_replace_one(&mut index);
}
});
}
fn run_index_insert_and_retain_dead_insert<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"key", 10u64);
index.insert(b"key", 20u64);
index.insert_and_retain(b"key", 30u64, |_| false);
assert_eq!(
index.get(b"key").copied().collect::<Vec<u64>>(),
Vec::<u64>::new()
);
assert_eq!(index.items(), 0);
assert_eq!(index.keys(), 0);
assert_eq!(index.pruned(), 2);
}
#[test_traced]
fn test_hash_index_insert_and_retain_dead_insert() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_insert_and_retain_dead_insert(&mut index);
});
}
#[test_traced]
fn test_ordered_index_insert_and_retain_dead_insert() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_insert_and_retain_dead_insert(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_insert_and_retain_dead_insert() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_insert_and_retain_dead_insert(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_insert_and_retain_dead_insert(&mut index);
}
});
}
fn run_index_insert_and_retain_single_value<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"both", 1u64);
index.insert_and_retain(b"both", 2u64, |_| true);
assert_eq!(index.get(b"both").copied().collect::<Vec<_>>(), vec![1, 2]);
index.insert(b"keep", 1u64);
index.insert_and_retain(b"keep", 2u64, |v| *v == 1);
assert_eq!(index.get(b"keep").copied().collect::<Vec<_>>(), vec![1]);
index.insert(b"drop", 1u64);
index.insert_and_retain(b"drop", 2u64, |_| false);
assert!(index.get(b"drop").next().is_none());
assert_eq!(index.keys(), 2); assert_eq!(index.items(), 3); assert_eq!(index.pruned(), 1); }
#[test_traced]
fn test_hash_index_insert_and_retain_single_value() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_insert_and_retain_single_value(&mut index);
});
}
#[test_traced]
fn test_ordered_index_insert_and_retain_single_value() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_insert_and_retain_single_value(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_insert_and_retain_single_value() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_insert_and_retain_single_value(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_insert_and_retain_single_value(&mut index);
}
});
}
fn run_index_cursor_across_threads<I>(index: Arc<Mutex<I>>)
where
I: Unordered<Value = u64> + Send + 'static,
{
{
let mut index = index.lock();
index.insert(b"test_key1", 100);
index.insert(b"test_key2", 200);
}
let index_clone = Arc::clone(&index);
let handle = thread::spawn(move || {
let result = {
let mut index = index_clone.lock();
let mut updated = false;
if let Some(mut cursor) = index.get_mut(b"test_key2") {
if cursor.find(|&value| value == 200) {
cursor.update(250);
updated = true;
}
}
updated
};
result
});
let result = handle.join().unwrap();
assert!(result);
{
let index = index.lock();
let values: Vec<u64> = index.get(b"test_key2").copied().collect();
assert!(values.contains(&100));
assert!(values.contains(&250));
assert!(!values.contains(&200));
}
}
#[test_traced]
fn test_hash_index_cursor_across_threads() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let index = Arc::new(Mutex::new(new_unordered(context)));
run_index_cursor_across_threads(index);
});
}
#[test_traced]
fn test_ordered_index_cursor_across_threads() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let index = Arc::new(Mutex::new(new_ordered(context)));
run_index_cursor_across_threads(index);
});
}
#[test_traced]
fn test_partitioned_index_cursor_across_threads() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let index = Arc::new(Mutex::new(new_partitioned_unordered(
context.child("unordered"),
)));
run_index_cursor_across_threads(index);
}
{
let index = Arc::new(Mutex::new(new_partitioned_ordered(
context.child("ordered"),
)));
run_index_cursor_across_threads(index);
}
});
}
fn run_index_remove_middle_then_next<I: Unordered<Value = u64>>(index: &mut I) {
for i in 0..4 {
index.insert(b"key", i);
}
let expected = values(index, b"key");
{
let mut cursor = index.get_mut(b"key").unwrap();
assert_eq!(*cursor.next().unwrap(), expected[0]);
assert_eq!(*cursor.next().unwrap(), expected[1]);
cursor.delete();
assert_eq!(*cursor.next().unwrap(), expected[2]);
cursor.delete();
}
assert_eq!(values(index, b"key"), vec![expected[0], expected[3]]);
}
#[test_traced]
fn test_hash_index_remove_middle_then_next() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_remove_middle_then_next(&mut index);
});
}
#[test_traced]
fn test_ordered_index_remove_middle_then_next() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_remove_middle_then_next(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_remove_middle_then_next() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_remove_middle_then_next(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_remove_middle_then_next(&mut index);
}
});
}
fn run_index_remove_to_nothing<I: Unordered<Value = u64>>(index: &mut I) {
for i in 0..4 {
index.insert(b"key", i);
}
{
let mut cursor = index.get_mut(b"key").unwrap();
let mut removed = Vec::new();
while let Some(value) = cursor.next().copied() {
removed.push(value);
cursor.delete();
}
removed.sort_unstable();
assert_eq!(removed, vec![0, 1, 2, 3]);
assert_eq!(cursor.next(), None);
}
assert_eq!(index.keys(), 0);
assert_eq!(index.items(), 0);
}
#[test_traced]
fn test_hash_index_remove_to_nothing() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_remove_to_nothing(&mut index);
});
}
#[test_traced]
fn test_ordered_index_remove_to_nothing() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_remove_to_nothing(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_remove_to_nothing() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_remove_to_nothing(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_remove_to_nothing(&mut index);
}
});
}
fn run_index_cursor_update_before_next_panics<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"key", 123);
let mut cursor = index.get_mut(b"key").unwrap();
cursor.update(321);
}
#[test_traced]
#[should_panic(expected = "must call Cursor::next()")]
fn test_hash_index_cursor_update_before_next_panics() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_cursor_update_before_next_panics(&mut index);
});
}
#[test_traced]
#[should_panic(expected = "must call Cursor::next()")]
fn test_ordered_index_cursor_update_before_next_panics() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_cursor_update_before_next_panics(&mut index);
});
}
#[test_traced]
#[should_panic(expected = "must call Cursor::next()")]
fn test_partitioned_index_cursor_update_before_next_panics() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_cursor_update_before_next_panics(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_cursor_update_before_next_panics(&mut index);
}
});
}
fn run_index_cursor_delete_before_next_panics<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"key", 123);
let mut cursor = index.get_mut(b"key").unwrap();
cursor.delete();
}
#[test_traced]
#[should_panic(expected = "must call Cursor::next()")]
fn test_hash_index_cursor_delete_before_next_panics() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_cursor_delete_before_next_panics(&mut index);
});
}
#[test_traced]
#[should_panic(expected = "must call Cursor::next()")]
fn test_ordered_index_cursor_delete_before_next_panics() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_cursor_delete_before_next_panics(&mut index);
});
}
#[test_traced]
#[should_panic(expected = "must call Cursor::next()")]
fn test_partitioned_index_cursor_delete_before_next_panics() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_cursor_delete_before_next_panics(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_cursor_delete_before_next_panics(&mut index);
}
});
}
fn run_index_cursor_update_after_done<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"key", 123);
let mut cursor = index.get_mut(b"key").unwrap();
assert_eq!(*cursor.next().unwrap(), 123);
assert!(cursor.next().is_none());
cursor.update(321);
}
#[test_traced]
#[should_panic(expected = "no active item in Cursor")]
fn test_hash_index_cursor_update_after_done() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_cursor_update_after_done(&mut index);
});
}
#[test_traced]
#[should_panic(expected = "no active item in Cursor")]
fn test_ordered_index_cursor_update_after_done() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_cursor_update_after_done(&mut index);
});
}
#[test_traced]
#[should_panic(expected = "no active item in Cursor")]
fn test_partitioned_index_cursor_update_after_done() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_cursor_update_after_done(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_cursor_update_after_done(&mut index);
}
});
}
fn run_index_cursor_insert_before_next<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"key", 123);
let mut cursor = index.get_mut(b"key").unwrap();
cursor.insert(321);
}
#[test_traced]
#[should_panic(expected = "must call Cursor::next()")]
fn test_hash_index_cursor_insert_before_next() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_cursor_insert_before_next(&mut index);
});
}
#[test_traced]
#[should_panic(expected = "must call Cursor::next()")]
fn test_ordered_index_cursor_insert_before_next() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_cursor_insert_before_next(&mut index);
});
}
#[test_traced]
#[should_panic(expected = "must call Cursor::next()")]
fn test_partitioned_index_cursor_insert_before_next() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_cursor_insert_before_next(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_cursor_insert_before_next(&mut index);
}
});
}
fn run_index_cursor_delete_after_done<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"key", 123);
let mut cursor = index.get_mut(b"key").unwrap();
assert_eq!(*cursor.next().unwrap(), 123);
assert!(cursor.next().is_none());
cursor.delete();
}
#[test_traced]
#[should_panic(expected = "no active item in Cursor")]
fn test_hash_index_cursor_delete_after_done() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_cursor_delete_after_done(&mut index);
});
}
#[test_traced]
#[should_panic(expected = "no active item in Cursor")]
fn test_ordered_index_cursor_delete_after_done() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_cursor_delete_after_done(&mut index);
});
}
#[test_traced]
#[should_panic(expected = "no active item in Cursor")]
fn test_partitioned_index_cursor_delete_after_done() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_cursor_delete_after_done(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_cursor_delete_after_done(&mut index);
}
});
}
fn run_index_cursor_insert_with_next<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"key", 123);
index.insert(b"key", 456);
let expected = values(index, b"key");
let mut cursor = index.get_mut(b"key").unwrap();
assert_eq!(*cursor.next().unwrap(), expected[0]);
assert_eq!(*cursor.next().unwrap(), expected[1]);
cursor.insert(789);
assert_eq!(cursor.next(), None);
cursor.insert(999);
drop(cursor);
let mut values = index.get(b"key").copied().collect::<Vec<_>>();
values.sort();
assert_eq!(values, vec![123, 456, 789, 999]);
}
#[test_traced]
fn test_hash_index_cursor_insert_with_next() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_cursor_insert_with_next(&mut index);
});
}
#[test_traced]
fn test_ordered_index_cursor_insert_with_next() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_cursor_insert_with_next(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_cursor_insert_with_next() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_cursor_insert_with_next(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_cursor_insert_with_next(&mut index);
}
});
}
fn run_index_cursor_double_delete<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"key", 123);
index.insert(b"key", 456);
let mut cursor = index.get_mut(b"key").unwrap();
assert!(cursor.next().is_some());
cursor.delete();
cursor.delete();
}
#[test_traced]
#[should_panic(expected = "must call Cursor::next()")]
fn test_hash_index_cursor_double_delete() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_cursor_double_delete(&mut index);
});
}
#[test_traced]
#[should_panic(expected = "must call Cursor::next()")]
fn test_ordered_index_cursor_double_delete() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_cursor_double_delete(&mut index);
});
}
fn run_index_cursor_delete_last_then_next<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"key", 1);
index.insert(b"key", 2);
let expected = values(index, b"key");
{
let mut cursor = index.get_mut(b"key").unwrap();
assert_eq!(*cursor.next().unwrap(), expected[0]);
assert_eq!(*cursor.next().unwrap(), expected[1]);
cursor.delete();
assert!(cursor.next().is_none());
assert!(cursor.next().is_none());
}
assert_eq!(index.keys(), 1);
assert_eq!(index.items(), 1);
}
#[test_traced]
fn test_hash_index_cursor_delete_last_then_next() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_cursor_delete_last_then_next(&mut index);
});
}
#[test_traced]
fn test_ordered_index_cursor_delete_last_then_next() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_cursor_delete_last_then_next(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_cursor_delete_last_then_next() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_cursor_delete_last_then_next(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_cursor_delete_last_then_next(&mut index);
}
});
}
fn run_index_delete_in_middle_then_continue<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"key", 1);
index.insert(b"key", 2);
index.insert(b"key", 3);
let expected = values(index, b"key");
let mut cur = index.get_mut(b"key").unwrap();
assert_eq!(*cur.next().unwrap(), expected[0]);
assert_eq!(*cur.next().unwrap(), expected[1]);
cur.delete();
assert_eq!(*cur.next().unwrap(), expected[2]);
assert!(cur.next().is_none());
assert!(cur.next().is_none());
}
#[test_traced]
fn test_hash_index_delete_in_middle_then_continue() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_delete_in_middle_then_continue(&mut index);
});
}
#[test_traced]
fn test_ordered_index_delete_in_middle_then_continue() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_delete_in_middle_then_continue(&mut index);
});
}
fn run_index_delete_first<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"key", 1);
index.insert(b"key", 2);
index.insert(b"key", 3);
let expected = values(index, b"key");
{
let mut cur = index.get_mut(b"key").unwrap();
assert_eq!(*cur.next().unwrap(), expected[0]);
cur.delete();
assert_eq!(*cur.next().unwrap(), expected[1]);
assert_eq!(*cur.next().unwrap(), expected[2]);
assert!(cur.next().is_none());
assert!(cur.next().is_none());
}
assert_eq!(values(index, b"key"), expected[1..]);
}
#[test_traced]
fn test_hash_index_delete_first() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_delete_first(&mut index);
});
}
#[test_traced]
fn test_ordered_index_delete_first() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_delete_first(&mut index);
});
}
fn run_index_delete_first_and_insert<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"key", 1);
index.insert(b"key", 2);
index.insert(b"key", 3);
let expected = values(index, b"key");
{
let mut cur = index.get_mut(b"key").unwrap();
assert_eq!(*cur.next().unwrap(), expected[0]);
cur.delete();
assert_eq!(*cur.next().unwrap(), expected[1]);
cur.insert(4);
assert_eq!(*cur.next().unwrap(), expected[2]);
assert!(cur.next().is_none());
assert!(cur.next().is_none());
}
assert_eq!(values(index, b"key"), vec![expected[1], 4, expected[2]]);
}
#[test_traced]
fn test_hash_index_delete_first_and_insert() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_delete_first_and_insert(&mut index);
});
}
#[test_traced]
fn test_ordered_index_delete_first_and_insert() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_delete_first_and_insert(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_delete_first_and_insert() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_delete_first_and_insert(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_delete_first_and_insert(&mut index);
}
});
}
fn run_index_insert_at_entry_then_next<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"key", 1);
index.insert(b"key", 2);
let expected = values(index, b"key");
let mut cur = index.get_mut(b"key").unwrap();
assert_eq!(*cur.next().unwrap(), expected[0]);
cur.insert(99);
assert_eq!(*cur.next().unwrap(), expected[1]);
assert!(cur.next().is_none());
}
#[test_traced]
fn test_hash_index_insert_at_entry_then_next() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_insert_at_entry_then_next(&mut index);
});
}
#[test_traced]
fn test_ordered_index_insert_at_entry_then_next() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_insert_at_entry_then_next(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_insert_at_entry_then_next() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_insert_at_entry_then_next(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_insert_at_entry_then_next(&mut index);
}
});
}
fn run_index_insert_at_entry_then_delete_head<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"key", 10);
index.insert(b"key", 20);
let mut cur = index.get_mut(b"key").unwrap();
assert!(cur.next().is_some());
cur.insert(15);
cur.delete();
}
#[test_traced]
#[should_panic(expected = "must call Cursor::next()")]
fn test_hash_index_insert_at_entry_then_delete_head() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_insert_at_entry_then_delete_head(&mut index);
});
}
#[test_traced]
#[should_panic(expected = "must call Cursor::next()")]
fn test_ordered_index_insert_at_entry_then_delete_head() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_insert_at_entry_then_delete_head(&mut index);
});
}
#[test_traced]
#[should_panic(expected = "must call Cursor::next()")]
fn test_partitioned_index_insert_at_entry_then_delete_head() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_insert_at_entry_then_delete_head(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_insert_at_entry_then_delete_head(&mut index);
}
});
}
fn run_index_delete_then_insert_without_next<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"key", 10);
index.insert(b"key", 20);
let mut cur = index.get_mut(b"key").unwrap();
assert!(cur.next().is_some());
assert!(cur.next().is_some());
cur.delete();
cur.insert(15);
}
#[test_traced]
#[should_panic(expected = "must call Cursor::next()")]
fn test_hash_index_delete_then_insert_without_next() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_delete_then_insert_without_next(&mut index);
});
}
#[test_traced]
#[should_panic(expected = "must call Cursor::next()")]
fn test_ordered_index_delete_then_insert_without_next() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_delete_then_insert_without_next(&mut index);
});
}
#[test_traced]
#[should_panic(expected = "must call Cursor::next()")]
fn test_partitioned_index_delete_then_insert_without_next() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_delete_then_insert_without_next(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_delete_then_insert_without_next(&mut index);
}
});
}
fn run_index_inserts_without_next<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"key", 10);
index.insert(b"key", 20);
let mut cur = index.get_mut(b"key").unwrap();
assert!(cur.next().is_some());
cur.insert(15);
cur.insert(25);
}
#[test_traced]
#[should_panic(expected = "must call Cursor::next()")]
fn test_hash_index_inserts_without_next() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_inserts_without_next(&mut index);
});
}
#[test_traced]
#[should_panic(expected = "must call Cursor::next()")]
fn test_ordered_index_inserts_without_next() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_inserts_without_next(&mut index);
});
}
#[test_traced]
#[should_panic(expected = "must call Cursor::next()")]
fn test_partitioned_index_inserts_without_next() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_inserts_without_next(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_inserts_without_next(&mut index);
}
});
}
fn run_index_delete_last_then_insert_while_done<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"k", 7);
{
let mut cur = index.get_mut(b"k").unwrap();
assert_eq!(*cur.next().unwrap(), 7);
cur.delete();
assert!(cur.next().is_none());
cur.insert(8);
assert!(cur.next().is_none());
cur.insert(9);
assert!(cur.next().is_none());
}
assert_eq!(index.keys(), 1);
assert_eq!(index.items(), 2);
assert_eq!(index.get(b"k").copied().collect::<Vec<_>>(), vec![8, 9]);
}
#[test_traced]
fn test_hash_index_delete_last_then_insert_while_done() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_delete_last_then_insert_while_done(&mut index);
});
}
#[test_traced]
fn test_ordered_index_delete_last_then_insert_while_done() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_delete_last_then_insert_while_done(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_delete_last_then_insert_while_done() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_delete_last_then_insert_while_done(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_delete_last_then_insert_while_done(&mut index);
}
});
}
fn run_index_drop_mid_iteration_preserves_chain<I: Unordered<Value = u64>>(index: &mut I) {
for i in 0..5 {
index.insert(b"z", i);
}
let expected = values(index, b"z");
{
let mut cur = index.get_mut(b"z").unwrap();
cur.next();
cur.next();
}
assert_eq!(values(index, b"z"), expected);
}
#[test_traced]
fn test_hash_index_drop_mid_iteration_preserves_chain() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_drop_mid_iteration_preserves_chain(&mut index);
});
}
#[test_traced]
fn test_ordered_index_drop_mid_iteration_preserves_chain() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_drop_mid_iteration_preserves_chain(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_drop_mid_iteration_preserves_chain() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_drop_mid_iteration_preserves_chain(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_drop_mid_iteration_preserves_chain(&mut index);
}
});
}
fn run_index_update_before_next_panics<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"p", 1);
let mut cur = index.get_mut(b"p").unwrap();
cur.update(2);
}
#[test_traced]
#[should_panic(expected = "must call Cursor::next()")]
fn test_hash_index_update_before_next_panics() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_update_before_next_panics(&mut index);
});
}
#[test_traced]
#[should_panic(expected = "must call Cursor::next()")]
fn test_ordered_index_update_before_next_panics() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_update_before_next_panics(&mut index);
});
}
#[test_traced]
#[should_panic(expected = "must call Cursor::next()")]
fn test_partitioned_index_update_before_next_panics() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_update_before_next_panics(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_update_before_next_panics(&mut index);
}
});
}
fn run_index_entry_replacement_not_a_collision<I: Unordered<Value = u64>>(index: &mut I) {
index.insert(b"a", 1);
{
let mut cur = index.get_mut(b"a").unwrap();
cur.next();
cur.delete();
cur.next();
cur.insert(2);
}
assert_eq!(index.keys(), 1);
assert_eq!(index.items(), 1);
}
#[test_traced]
fn test_hash_index_entry_replacement_not_a_collision() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_entry_replacement_not_a_collision(&mut index);
});
}
#[test_traced]
fn test_ordered_index_entry_replacement_not_a_collision() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_entry_replacement_not_a_collision(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_entry_replacement_not_a_collision() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_entry_replacement_not_a_collision(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_entry_replacement_not_a_collision(&mut index);
}
});
}
fn run_index_large_collision_chain<I: Unordered<Value = u64>>(index: &mut I) {
const ITEMS: usize = 50_000;
for i in 0..ITEMS {
index.insert(b"", i as u64);
}
assert_eq!(index.keys(), 1);
assert_eq!(index.items(), ITEMS);
let expected: Vec<u64> = (0..ITEMS as u64).collect();
assert_values(index, b"", &expected);
}
#[test_traced]
fn test_hash_index_large_collision_chain() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_unordered(context);
run_index_large_collision_chain(&mut index);
});
}
#[test_traced]
fn test_ordered_index_large_collision_chain() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
let mut index = new_ordered(context);
run_index_large_collision_chain(&mut index);
});
}
#[test_traced]
fn test_partitioned_index_large_collision_chain() {
let runner = deterministic::Runner::default();
runner.start(|context| async move {
{
let mut index = new_partitioned_unordered(context.child("unordered"));
run_index_large_collision_chain(&mut index);
}
{
let mut index = new_partitioned_ordered(context.child("ordered"));
run_index_large_collision_chain(&mut index);
}
});
}
}