Skip to content

Commit

Permalink
Add range_arc() and get_arc()
Browse files Browse the repository at this point in the history
These methods return reference counted iterators from read only
transactions
  • Loading branch information
cberner committed Dec 21, 2023
1 parent 4080f98 commit 20142b5
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 0 deletions.
39 changes: 39 additions & 0 deletions src/multimap_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1296,6 +1296,45 @@ impl<'txn, K: RedbKey + 'static, V: RedbKey + 'static> ReadOnlyMultimapTable<'tx
_lifetime: Default::default(),
})
}

/// This method is like `get()`, but the iterator is reference counted and keeps the transaction
/// alive until it is dropped.
pub fn get_arc<'a>(
&self,
key: impl Borrow<K::SelfType<'a>>,
) -> Result<MultimapValue<'static, V>>
where
K: 'a,
{
let iter = if let Some(collection) = self.tree.get(key.borrow())? {
DynamicCollection::iter(collection, self.transaction_guard.clone(), self.mem.clone())?
} else {
MultimapValue::new_subtree(
BtreeRangeIter::new::<RangeFull, &V::SelfType<'_>>(&(..), None, self.mem.clone())?,
self.transaction_guard.clone(),
)
};

Ok(iter)
}

/// This method is like `range()`, but the iterator is reference counted and keeps the transaction
/// alive until it is dropped.
pub fn range_arc<'a, KR>(
&self,
range: impl RangeBounds<KR> + 'a,
) -> Result<MultimapRange<'static, K, V>>
where
K: 'a,
KR: Borrow<K::SelfType<'a>> + 'a,
{
let inner = self.tree.range(&range)?;
Ok(MultimapRange::new(
inner,
self.transaction_guard.clone(),
self.mem.clone(),
))
}
}

impl<'txn, K: RedbKey + 'static, V: RedbKey + 'static> ReadableMultimapTable<K, V>
Expand Down
15 changes: 15 additions & 0 deletions src/table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,21 @@ impl<'txn, K: RedbKey + 'static, V: RedbValue + 'static> ReadOnlyTable<'txn, K,
_lifetime: Default::default(),
})
}

/// This method is like `range()`, but the iterator is reference counted and keeps the transaction
/// alive until it is dropped.
pub fn range_arc<'a, KR>(
&self,
range: impl RangeBounds<KR> + 'a,
) -> Result<Range<'static, K, V>>
where
K: 'a,
KR: Borrow<K::SelfType<'a>> + 'a,
{
self.tree
.range(&range)
.map(|x| Range::new(x, self.transaction_guard.clone()))
}
}

impl<'txn, K: RedbKey + 'static, V: RedbValue + 'static> ReadableTable<K, V>
Expand Down
24 changes: 24 additions & 0 deletions tests/basic_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1246,6 +1246,30 @@ fn range_lifetime() {
assert!(iter.next().is_none());
}

#[test]
fn range_arc() {
let tmpfile = create_tempfile();
let db = Database::create(tmpfile.path()).unwrap();

let definition: TableDefinition<&str, &str> = TableDefinition::new("x");

let write_txn = db.begin_write().unwrap();
{
let mut table = write_txn.open_table(definition).unwrap();
table.insert("hello", "world").unwrap();
}
write_txn.commit().unwrap();

let mut iter = {
let read_txn = db.begin_read().unwrap();
let table = read_txn.open_table(definition).unwrap();
let start = "hello".to_string();
table.range_arc::<&str>(start.as_str()..).unwrap()
};
assert_eq!(iter.next().unwrap().unwrap().1.value(), "world");
assert!(iter.next().is_none());
}

#[test]
fn drain_lifetime() {
let tmpfile = create_tempfile();
Expand Down
58 changes: 58 additions & 0 deletions tests/multimap_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,64 @@ fn range_lifetime() {
assert!(iter.next().is_none());
}

#[test]
fn range_arc_lifetime() {
let tmpfile = create_tempfile();
let db = Database::create(tmpfile.path()).unwrap();

let definition: MultimapTableDefinition<&str, &str> = MultimapTableDefinition::new("x");

let write_txn = db.begin_write().unwrap();
{
let mut table = write_txn.open_multimap_table(definition).unwrap();
table.insert("hello", "world").unwrap();
}
write_txn.commit().unwrap();

let mut iter = {
let read_txn = db.begin_read().unwrap();
let table = read_txn.open_multimap_table(definition).unwrap();
let start = "hello".to_string();
table.range_arc::<&str>(start.as_str()..).unwrap()
};
assert_eq!(
iter.next()
.unwrap()
.unwrap()
.1
.next()
.unwrap()
.unwrap()
.value(),
"world"
);
assert!(iter.next().is_none());
}

#[test]
fn get_arc_lifetime() {
let tmpfile = create_tempfile();
let db = Database::create(tmpfile.path()).unwrap();

let definition: MultimapTableDefinition<&str, &str> = MultimapTableDefinition::new("x");

let write_txn = db.begin_write().unwrap();
{
let mut table = write_txn.open_multimap_table(definition).unwrap();
table.insert("hello", "world").unwrap();
}
write_txn.commit().unwrap();

let mut iter = {
let read_txn = db.begin_read().unwrap();
let table = read_txn.open_multimap_table(definition).unwrap();
let start = "hello".to_string();
table.get_arc(start.as_str()).unwrap()
};
assert_eq!(iter.next().unwrap().unwrap().value(), "world");
assert!(iter.next().is_none());
}

#[test]
fn delete() {
let tmpfile = create_tempfile();
Expand Down

0 comments on commit 20142b5

Please sign in to comment.