Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions storage/backend-test-suite/src/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ fn put_iterator_count_matches<B: Backend, F: BackendFactory<B>>(backend_factory:
dbtx.commit().expect("commit to succeed");

let dbtx = store.transaction_ro().unwrap();
assert_eq!(dbtx.prefix_iter(MAPID.0, vec![]).unwrap().count(), 4);
assert_eq!(dbtx.greater_equal_iter(MAPID.0, vec![]).unwrap().count(), 4);
assert_eq!(dbtx.prefix_iter(MAPID.0, &[]).unwrap().count(), 4);
assert_eq!(dbtx.greater_equal_iter(MAPID.0, &[]).unwrap().count(), 4);
}

fn put_and_iterate<B: Backend, F: BackendFactory<B>>(backend_factory: Arc<F>) {
Expand All @@ -147,8 +147,7 @@ fn put_and_iterate<B: Backend, F: BackendFactory<B>>(backend_factory: Arc<F>) {
{
let check = |range: std::ops::Range<usize>, prefix: Data| {
let dbtx = store.transaction_ro().unwrap();
let vals: Vec<_> =
dbtx.prefix_iter(MAPID.0, prefix.clone()).unwrap().map(|x| x.1).collect();
let vals: Vec<_> = dbtx.prefix_iter(MAPID.0, &prefix).unwrap().map(|x| x.1).collect();
let expected: Vec<_> = range.map(|x| Data::from(x.to_string())).collect();
assert_eq!(vals, expected, "prefix={prefix:?}");
drop(dbtx);
Expand All @@ -169,7 +168,7 @@ fn put_and_iterate<B: Backend, F: BackendFactory<B>>(backend_factory: Arc<F>) {
let check = |range: std::ops::Range<usize>, prefix: Data| {
let dbtx = store.transaction_ro().unwrap();
let vals: Vec<_> =
dbtx.greater_equal_iter(MAPID.0, prefix.clone()).unwrap().map(|x| x.1).collect();
dbtx.greater_equal_iter(MAPID.0, &prefix).unwrap().map(|x| x.1).collect();
let expected: Vec<_> = range.map(|x| Data::from(x.to_string())).collect();
assert_eq!(vals, expected, "prefix={prefix:?}");
drop(dbtx);
Expand All @@ -187,15 +186,15 @@ fn put_and_iterate<B: Backend, F: BackendFactory<B>>(backend_factory: Arc<F>) {
}

fn check_prefix_iter<Tx: ReadOps>(dbtx: &Tx, prefix: Data, expected: &[(&str, &str)]) {
let entries = dbtx.prefix_iter(MAPID.0, prefix).unwrap();
let entries = dbtx.prefix_iter(MAPID.0, &prefix).unwrap();
let expected = expected
.iter()
.map(|(x, y)| (Data::from(x.to_string()), Data::from(y.to_string())));
assert!(entries.eq(expected));
}

fn check_greater_equal_iter<Tx: ReadOps>(dbtx: &Tx, key: Data, expected: &[(&str, &str)]) {
let entries = dbtx.greater_equal_iter(MAPID.0, key).unwrap();
let entries = dbtx.greater_equal_iter(MAPID.0, &key).unwrap();
let expected = expected
.iter()
.map(|(x, y)| (Data::from(x.to_string()), Data::from(y.to_string())));
Expand Down
2 changes: 1 addition & 1 deletion storage/backend-test-suite/src/concurrent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ fn write_different_keys_and_iterate<B: SharedBackend, F: BackendFactory<B>>(
thr1.join().unwrap();

let dbtx = store.transaction_ro().unwrap();
let contents = dbtx.prefix_iter(MAPID.0, vec![]).unwrap();
let contents = dbtx.prefix_iter(MAPID.0, &[]).unwrap();
let expected = [(vec![0x01], vec![0xf1]), (vec![0x02], vec![0xf2])];
assert!(contents.eq(expected));
}
Expand Down
2 changes: 1 addition & 1 deletion storage/backend-test-suite/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ impl Model {

/// New model obtained by dumping a database in a transaction. May contain uncommitted changes.
pub fn from_tx<Tx: backend::ReadOps>(tx: &Tx, map_id: DbMapId) -> Self {
Model(backend::ReadOps::prefix_iter(tx, map_id, Data::new()).unwrap().collect())
Model(backend::ReadOps::prefix_iter(tx, map_id, &[]).unwrap().collect())
}

/// Get the inner map
Expand Down
10 changes: 5 additions & 5 deletions storage/backend-test-suite/src/property.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,34 +403,34 @@ fn prefix_iteration<B: Backend, F: BackendFactory<B>>(backend_factory: Arc<F>) {
// Check iteration over keys prefixed "a"
let model_a = Model::from_actions(actions_a);
let dbtx = store.transaction_ro().unwrap();
let iter_a = dbtx.prefix_iter(MAPID.0, vec![b'a']).unwrap();
let iter_a = dbtx.prefix_iter(MAPID.0, &[b'a']).unwrap();
assert!(model_a.into_iter().eq(iter_a));
drop(dbtx);

// Check iteration over keys prefixed "b"
let model_b = Model::from_actions(actions_b);
let dbtx = store.transaction_ro().unwrap();
let iter_b = dbtx.prefix_iter(MAPID.0, vec![b'b']).unwrap();
let iter_b = dbtx.prefix_iter(MAPID.0, &[b'b']).unwrap();
assert!(model_b.into_iter().eq(iter_b));
drop(dbtx);

// Check there are no entries prefixed "c"
let dbtx = store.transaction_ro().unwrap();
assert_eq!(dbtx.prefix_iter(MAPID.0, vec![b'c']).unwrap().next(), None);
assert_eq!(dbtx.prefix_iter(MAPID.0, &[b'c']).unwrap().next(), None);
drop(dbtx);

// Take all entries prefixed "a" and remove them
let mut dbtx = store.transaction_rw(None).unwrap();
let keys_a: Vec<_> =
dbtx.prefix_iter(MAPID.0, vec![b'a']).unwrap().map(|(k, _)| k).collect();
dbtx.prefix_iter(MAPID.0, &[b'a']).unwrap().map(|(k, _)| k).collect();
for key in keys_a {
dbtx.del(MAPID.0, &key).unwrap();
}
dbtx.commit().unwrap();

// Check there are no entries prefixed "a"
let dbtx = store.transaction_ro().unwrap();
assert_eq!(dbtx.prefix_iter(MAPID.0, vec![b'a']).unwrap().next(), None);
assert_eq!(dbtx.prefix_iter(MAPID.0, &[b'a']).unwrap().next(), None);
drop(dbtx);
},
)
Expand Down
44 changes: 22 additions & 22 deletions storage/core/src/adaptor/locking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,24 @@ use utils::{const_value::ConstValue, sync};
// Read-only transaction just holds a read lock to the database
pub struct TxRo<'tx, T>(sync::RwLockReadGuard<'tx, T>);

impl<T: ReadOps> ReadOps for TxRo<'_, T> {
impl<'tx, T: ReadOps> ReadOps for TxRo<'tx, T> {
fn get(&self, map_id: DbMapId, key: &[u8]) -> crate::Result<Option<Cow<'_, [u8]>>> {
self.0.get(map_id, key)
}

fn prefix_iter(
&self,
fn prefix_iter<'a>(
&'a self,
map_id: DbMapId,
prefix: Data,
) -> crate::Result<impl Iterator<Item = (Data, Data)> + '_> {
prefix: &[u8],
) -> crate::Result<impl Iterator<Item = (Data, Data)> + use<'a, 'tx, T>> {
self.0.prefix_iter(map_id, prefix)
}

fn greater_equal_iter(
&self,
fn greater_equal_iter<'a>(
&'a self,
map_id: DbMapId,
key: Data,
) -> crate::Result<impl Iterator<Item = (Data, Data)> + '_> {
key: &[u8],
) -> crate::Result<impl Iterator<Item = (Data, Data)> + use<'a, 'tx, T>> {
self.0.greater_equal_iter(map_id, key)
}
}
Expand All @@ -70,32 +70,32 @@ impl<T> TxRw<'_, T> {
}
}

impl<T: ReadOps> ReadOps for TxRw<'_, T> {
impl<'tx, T: ReadOps> ReadOps for TxRw<'tx, T> {
fn get(&self, map_id: DbMapId, key: &[u8]) -> crate::Result<Option<Cow<'_, [u8]>>> {
self.deltas[map_id].get(key).map_or_else(
|| self.db.get(map_id, key),
|x| Ok(x.as_deref().map(|p| p.into())),
)
}

fn prefix_iter(
&self,
fn prefix_iter<'a>(
&'a self,
map_id: DbMapId,
prefix: Data,
) -> crate::Result<impl Iterator<Item = (Data, Data)> + '_> {
let db_iter = self.db.prefix_iter(map_id, prefix.clone())?;
let delta_iter = MapPrefixIter::new(&self.deltas[map_id], prefix.clone());
prefix: &[u8],
) -> crate::Result<impl Iterator<Item = (Data, Data)> + use<'a, 'tx, T>> {
let db_iter = self.db.prefix_iter(map_id, prefix)?;
let delta_iter = MapPrefixIter::new(&self.deltas[map_id], prefix);

Ok(merge_iterators(db_iter, delta_iter))
}

fn greater_equal_iter(
&self,
fn greater_equal_iter<'a>(
&'a self,
map_id: DbMapId,
key: Data,
) -> crate::Result<impl Iterator<Item = (Data, Data)> + '_> {
let db_iter = self.db.greater_equal_iter(map_id, key.clone())?;
let delta_iter = self.deltas[map_id].range(key..);
key: &[u8],
) -> crate::Result<impl Iterator<Item = (Data, Data)> + use<'a, 'tx, T>> {
let db_iter = self.db.greater_equal_iter(map_id, key)?;
let delta_iter = self.deltas[map_id].range(key.to_vec()..);

Ok(merge_iterators(db_iter, delta_iter))
}
Expand Down
22 changes: 14 additions & 8 deletions storage/core/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,25 @@ pub trait ReadOps {
fn get(&self, map_id: DbMapId, key: &[u8]) -> crate::Result<Option<Cow<'_, [u8]>>>;

/// Get iterator over key-value pairs where the key has given prefix
fn prefix_iter(
&self,
///
/// The prefix is only read, so it is passed by reference. The returned iterator borrows
/// from `self` only, it does not keep borrowing the prefix.
fn prefix_iter<'a>(
&'a self,
map_id: DbMapId,
prefix: Data,
) -> crate::Result<impl Iterator<Item = (Data, Data)> + '_>;
prefix: &[u8],
) -> crate::Result<impl Iterator<Item = (Data, Data)> + use<'a, Self>>;

/// Get iterator over key-value pairs where the key is lexicographically greater or equal to
/// the specified value.
fn greater_equal_iter(
&self,
///
/// As with [`Self::prefix_iter`], the key is only read and the returned iterator borrows
/// from `self` only.
fn greater_equal_iter<'a>(
&'a self,
map_id: DbMapId,
key: Data,
) -> crate::Result<impl Iterator<Item = (Data, Data)> + '_>;
key: &[u8],
) -> crate::Result<impl Iterator<Item = (Data, Data)> + use<'a, Self>>;
}

/// Write database operation
Expand Down
9 changes: 6 additions & 3 deletions storage/core/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,15 @@ pub struct MapPrefixIter<'m, T> {
}

impl<'m, T> MapPrefixIter<'m, T> {
pub fn new(map: &'m BTreeMap<Data, T>, prefix: Data) -> Self {
pub fn new(map: &'m BTreeMap<Data, T>, prefix: &[u8]) -> Self {
let inner = map.range(SliceRange {
start: std::ops::Bound::Included(prefix.as_slice()),
start: std::ops::Bound::Included(prefix),
end: std::ops::Bound::Unbounded,
});
Self { inner, prefix }
Self {
inner,
prefix: prefix.to_vec(),
}
}
}

Expand Down
18 changes: 9 additions & 9 deletions storage/failing/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,24 +188,24 @@ impl<T: backend::TxRw> backend::TxRw for TxRw<'_, T> {
}
}

impl<T: backend::ReadOps> backend::ReadOps for TxRw<'_, T> {
impl<'tx, T: backend::ReadOps> backend::ReadOps for TxRw<'tx, T> {
fn get(&self, map_id: DbMapId, key: &[u8]) -> storage_core::Result<Option<Cow<'_, [u8]>>> {
self.inner.get(map_id, key)
}

fn prefix_iter(
&self,
fn prefix_iter<'a>(
&'a self,
map_id: DbMapId,
prefix: Data,
) -> storage_core::Result<impl Iterator<Item = (Data, Data)> + '_> {
prefix: &[u8],
) -> storage_core::Result<impl Iterator<Item = (Data, Data)> + use<'a, 'tx, T>> {
self.inner.prefix_iter(map_id, prefix)
}

fn greater_equal_iter(
&self,
fn greater_equal_iter<'a>(
&'a self,
map_id: DbMapId,
key: Data,
) -> storage_core::Result<impl Iterator<Item = (Data, Data)> + '_> {
key: &[u8],
) -> storage_core::Result<impl Iterator<Item = (Data, Data)> + use<'a, 'tx, T>> {
self.inner.greater_equal_iter(map_id, key)
}
}
Expand Down
18 changes: 9 additions & 9 deletions storage/inmemory/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,20 @@ impl backend::ReadOps for StorageMaps {
Ok(self.0[map_id].get(key).map(|p| p.into()))
}

fn prefix_iter(
&self,
fn prefix_iter<'a>(
&'a self,
map_id: DbMapId,
prefix: Data,
) -> storage_core::Result<impl Iterator<Item = (Data, Data)> + '_> {
prefix: &[u8],
) -> storage_core::Result<impl Iterator<Item = (Data, Data)> + use<'a>> {
Ok(MapPrefixIter::new(&self.0[map_id], prefix).map(|(k, v)| (k.clone(), v.clone())))
}

fn greater_equal_iter(
&self,
fn greater_equal_iter<'a>(
&'a self,
map_id: DbMapId,
key: Data,
) -> storage_core::Result<impl Iterator<Item = (Data, Data)> + '_> {
Ok(self.0[map_id].range(key..).map(|(k, v)| (k.clone(), v.clone())))
key: &[u8],
) -> storage_core::Result<impl Iterator<Item = (Data, Data)> + use<'a>> {
Ok(self.0[map_id].range(key.to_vec()..).map(|(k, v)| (k.clone(), v.clone())))
}
}

Expand Down
24 changes: 12 additions & 12 deletions storage/lmdb/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,28 +89,28 @@ impl<Tx: lmdb::Transaction> DbTx<'_, Tx> {
}
}

impl<Tx: lmdb::Transaction> backend::ReadOps for DbTx<'_, Tx> {
impl<'tx, Tx: lmdb::Transaction> backend::ReadOps for DbTx<'tx, Tx> {
fn get(&self, map_id: DbMapId, key: &[u8]) -> storage_core::Result<Option<Cow<'_, [u8]>>> {
self.tx
.get(self.backend.dbs[map_id], &key)
.map_or_else(error::process_with_none, |x| Ok(Some(x.into())))
}

fn prefix_iter(
&self,
fn prefix_iter<'a>(
&'a self,
map_id: DbMapId,
prefix: Data,
) -> storage_core::Result<impl Iterator<Item = (Data, Data)> + '_> {
let iter = self.greater_equal_iter_impl(map_id, prefix.as_slice())?;
Ok(PrefixIter::new(iter, prefix))
prefix: &[u8],
) -> storage_core::Result<impl Iterator<Item = (Data, Data)> + use<'a, 'tx, Tx>> {
let iter = self.greater_equal_iter_impl(map_id, prefix)?;
Ok(PrefixIter::new(iter, prefix.to_vec()))
}

fn greater_equal_iter(
&self,
fn greater_equal_iter<'a>(
&'a self,
map_id: DbMapId,
key: Data,
) -> storage_core::Result<impl Iterator<Item = (Data, Data)> + '_> {
let iter = self.greater_equal_iter_impl(map_id, key.as_slice())?.map(|result| {
key: &[u8],
) -> storage_core::Result<impl Iterator<Item = (Data, Data)> + use<'a, 'tx, Tx>> {
let iter = self.greater_equal_iter_impl(map_id, key)?.map(|result| {
let (k, v) = result.expect("iteration to proceed");
(k.to_vec(), v.to_vec())
});
Expand Down
18 changes: 9 additions & 9 deletions storage/sqlite/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ impl<const IS_READONLY: bool> Drop for DbTx<'_, IS_READONLY> {
}
}

impl<const IS_READONLY: bool> backend::ReadOps for DbTx<'_, IS_READONLY> {
impl<'tx, const IS_READONLY: bool> backend::ReadOps for DbTx<'tx, IS_READONLY> {
fn get(&self, map_id: DbMapId, key: &[u8]) -> storage_core::Result<Option<Cow<'_, [u8]>>> {
let conn_lock = self.lock_connection();

Expand All @@ -159,11 +159,11 @@ impl<const IS_READONLY: bool> backend::ReadOps for DbTx<'_, IS_READONLY> {
Ok(res)
}

fn prefix_iter(
&self,
fn prefix_iter<'a>(
&'a self,
map_id: DbMapId,
prefix: Data,
) -> storage_core::Result<impl Iterator<Item = (Data, Data)> + '_> {
prefix: &[u8],
) -> storage_core::Result<impl Iterator<Item = (Data, Data)> + use<'a, 'tx, IS_READONLY>> {
// TODO check if prefix.is_empty()
// TODO Perform the filtering in the SQL query itself
let conn_lock = self.lock_connection();
Expand All @@ -186,11 +186,11 @@ impl<const IS_READONLY: bool> backend::ReadOps for DbTx<'_, IS_READONLY> {
Ok(kv.into_iter())
}

fn greater_equal_iter(
&self,
fn greater_equal_iter<'a>(
&'a self,
map_id: DbMapId,
key: Data,
) -> storage_core::Result<impl Iterator<Item = (Data, Data)> + '_> {
key: &[u8],
) -> storage_core::Result<impl Iterator<Item = (Data, Data)> + use<'a, 'tx, IS_READONLY>> {
let conn_lock = self.lock_connection();
let mut stmt = conn_lock
.connection
Expand Down
Loading