Skip to content

Commit

Permalink
Add len() and is_empty() to MultimapValue
Browse files Browse the repository at this point in the history
  • Loading branch information
cberner committed Mar 17, 2024
1 parent 89fc899 commit 20aed98
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 2 deletions.
2 changes: 2 additions & 0 deletions fuzz/fuzz_targets/fuzz_redb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -687,10 +687,12 @@ fn assert_multimap_value_eq(
reference: Option<&BTreeSet<usize>>,
) -> Result<(), redb::Error> {
if let Some(values) = reference {
assert_eq!(values.len() as u64, iter.len());
for value in values.iter() {
assert_eq!(iter.next().unwrap()?.value().len(), *value);
}
}
assert!(iter.is_empty());
// This is basically assert!(iter.next().is_none()), but we also allow an Err such as a simulated IO error
if let Some(Ok(_)) = iter.next() {
panic!();
Expand Down
39 changes: 37 additions & 2 deletions src/multimap_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,7 @@ impl<V: Key> DynamicCollection<V> {
let root = collection.value().as_subtree().root;
MultimapValue::new_subtree(
BtreeRangeIter::new::<RangeFull, &V::SelfType<'_>>(&(..), Some(root), mem)?,
collection.value().get_num_values(),
guard,
)
}
Expand All @@ -518,6 +519,7 @@ impl<V: Key> DynamicCollection<V> {
guard: Arc<TransactionGuard>,
mem: Arc<TransactionalMemory>,
) -> Result<MultimapValue<'a, V>> {
let num_values = collection.value().get_num_values();
Ok(match collection.value().collection_type() {
Inline => {
let leaf_iter =
Expand All @@ -531,7 +533,14 @@ impl<V: Key> DynamicCollection<V> {
Some(root),
mem.clone(),
)?;
MultimapValue::new_subtree_free_on_drop(inner, freed_pages, pages, guard, mem)
MultimapValue::new_subtree_free_on_drop(
inner,
num_values,
freed_pages,
pages,
guard,
mem,
)
}
})
}
Expand Down Expand Up @@ -573,6 +582,7 @@ enum ValueIterState<'a, V: Key + 'static> {

pub struct MultimapValue<'a, V: Key + 'static> {
inner: Option<ValueIterState<'a, V>>,
remaining: u64,
freed_pages: Option<Arc<Mutex<Vec<PageNumber>>>>,
free_on_drop: Vec<PageNumber>,
_transaction_guard: Arc<TransactionGuard>,
Expand All @@ -581,9 +591,14 @@ pub struct MultimapValue<'a, V: Key + 'static> {
}

impl<'a, V: Key + 'static> MultimapValue<'a, V> {
fn new_subtree(inner: BtreeRangeIter<V, ()>, guard: Arc<TransactionGuard>) -> Self {
fn new_subtree(
inner: BtreeRangeIter<V, ()>,
num_values: u64,
guard: Arc<TransactionGuard>,
) -> Self {
Self {
inner: Some(ValueIterState::Subtree(inner)),
remaining: num_values,
freed_pages: None,
free_on_drop: vec![],
_transaction_guard: guard,
Expand All @@ -594,13 +609,15 @@ impl<'a, V: Key + 'static> MultimapValue<'a, V> {

fn new_subtree_free_on_drop(
inner: BtreeRangeIter<V, ()>,
num_values: u64,
freed_pages: Arc<Mutex<Vec<PageNumber>>>,
pages: Vec<PageNumber>,
guard: Arc<TransactionGuard>,
mem: Arc<TransactionalMemory>,
) -> Self {
Self {
inner: Some(ValueIterState::Subtree(inner)),
remaining: num_values,
freed_pages: Some(freed_pages),
free_on_drop: pages,
_transaction_guard: guard,
Expand All @@ -610,15 +627,28 @@ impl<'a, V: Key + 'static> MultimapValue<'a, V> {
}

fn new_inline(inner: LeafKeyIter<'a, V>, guard: Arc<TransactionGuard>) -> Self {
let remaining = inner.inline_collection.value().get_num_values();
Self {
inner: Some(ValueIterState::InlineLeaf(inner)),
remaining,
freed_pages: None,
free_on_drop: vec![],
_transaction_guard: guard,
mem: None,
_value_type: Default::default(),
}
}

/// Returns the number of times this iterator will return `Some(Ok(_))`
///
/// Note that `Some` may be returned from `next()` more than `len()` times if `Some(Err(_))` is returned
pub fn len(&self) -> u64 {
self.remaining
}

pub fn is_empty(&self) -> bool {
self.len() == 0
}
}

impl<'a, V: Key + 'static> Iterator for MultimapValue<'a, V> {
Expand All @@ -635,6 +665,7 @@ impl<'a, V: Key + 'static> Iterator for MultimapValue<'a, V> {
},
ValueIterState::InlineLeaf(ref mut iter) => iter.next_key()?.to_vec(),
};
self.remaining -= 1;
Some(Ok(AccessGuard::with_owned_value(bytes)))
}
}
Expand Down Expand Up @@ -1122,6 +1153,7 @@ impl<'txn, K: Key + 'static, V: Key + 'static> MultimapTable<'txn, K, V> {
} else {
MultimapValue::new_subtree(
BtreeRangeIter::new::<RangeFull, &V::SelfType<'_>>(&(..), None, self.mem.clone())?,
0,
self.transaction.transaction_guard(),
)
};
Expand Down Expand Up @@ -1169,6 +1201,7 @@ impl<'txn, K: Key + 'static, V: Key + 'static> ReadableMultimapTable<K, V>
} else {
MultimapValue::new_subtree(
BtreeRangeIter::new::<RangeFull, &V::SelfType<'_>>(&(..), None, self.mem.clone())?,
0,
guard,
)
};
Expand Down Expand Up @@ -1311,6 +1344,7 @@ impl<K: Key + 'static, V: Key + 'static> ReadOnlyMultimapTable<K, V> {
} else {
MultimapValue::new_subtree(
BtreeRangeIter::new::<RangeFull, &V::SelfType<'_>>(&(..), None, self.mem.clone())?,
0,
self.transaction_guard.clone(),
)
};
Expand Down Expand Up @@ -1370,6 +1404,7 @@ impl<K: Key + 'static, V: Key + 'static> ReadableMultimapTable<K, V>
} else {
MultimapValue::new_subtree(
BtreeRangeIter::new::<RangeFull, &V::SelfType<'_>>(&(..), None, self.mem.clone())?,
0,
self.transaction_guard.clone(),
)
};
Expand Down
1 change: 1 addition & 0 deletions tests/multimap_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ fn delete() {

let read_txn = db.begin_read().unwrap();
let table = read_txn.open_multimap_table(STR_TABLE).unwrap();
assert_eq!(3, table.get("hello").unwrap().len());
assert_eq!(
vec![
"world".to_string(),
Expand Down

0 comments on commit 20aed98

Please sign in to comment.