diff --git a/storage/backend-test-suite/src/basic.rs b/storage/backend-test-suite/src/basic.rs index b9ba33678..ddba6e93f 100644 --- a/storage/backend-test-suite/src/basic.rs +++ b/storage/backend-test-suite/src/basic.rs @@ -122,8 +122,8 @@ fn put_iterator_count_matches>(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>(backend_factory: Arc) { @@ -147,8 +147,7 @@ fn put_and_iterate>(backend_factory: Arc) { { let check = |range: std::ops::Range, 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); @@ -169,7 +168,7 @@ fn put_and_iterate>(backend_factory: Arc) { let check = |range: std::ops::Range, 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); @@ -187,7 +186,7 @@ fn put_and_iterate>(backend_factory: Arc) { } fn check_prefix_iter(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()))); @@ -195,7 +194,7 @@ fn check_prefix_iter(dbtx: &Tx, prefix: Data, expected: &[(&str, &s } fn check_greater_equal_iter(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()))); diff --git a/storage/backend-test-suite/src/concurrent.rs b/storage/backend-test-suite/src/concurrent.rs index 7bcd81835..0d1e69c9f 100644 --- a/storage/backend-test-suite/src/concurrent.rs +++ b/storage/backend-test-suite/src/concurrent.rs @@ -209,7 +209,7 @@ fn write_different_keys_and_iterate>( 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)); } diff --git a/storage/backend-test-suite/src/model.rs b/storage/backend-test-suite/src/model.rs index 58136fb40..6d2eae9dd 100644 --- a/storage/backend-test-suite/src/model.rs +++ b/storage/backend-test-suite/src/model.rs @@ -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: &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 diff --git a/storage/backend-test-suite/src/property.rs b/storage/backend-test-suite/src/property.rs index 5e88bc8b7..8eca9aa5a 100644 --- a/storage/backend-test-suite/src/property.rs +++ b/storage/backend-test-suite/src/property.rs @@ -403,26 +403,26 @@ fn prefix_iteration>(backend_factory: Arc) { // 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(); } @@ -430,7 +430,7 @@ fn prefix_iteration>(backend_factory: Arc) { // 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); }, ) diff --git a/storage/core/src/adaptor/locking.rs b/storage/core/src/adaptor/locking.rs index 1babeaa78..1d5a98a28 100644 --- a/storage/core/src/adaptor/locking.rs +++ b/storage/core/src/adaptor/locking.rs @@ -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 ReadOps for TxRo<'_, T> { +impl<'tx, T: ReadOps> ReadOps for TxRo<'tx, T> { fn get(&self, map_id: DbMapId, key: &[u8]) -> crate::Result>> { self.0.get(map_id, key) } - fn prefix_iter( - &self, + fn prefix_iter<'a>( + &'a self, map_id: DbMapId, - prefix: Data, - ) -> crate::Result + '_> { + prefix: &[u8], + ) -> crate::Result + 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 + '_> { + key: &[u8], + ) -> crate::Result + use<'a, 'tx, T>> { self.0.greater_equal_iter(map_id, key) } } @@ -70,7 +70,7 @@ impl TxRw<'_, T> { } } -impl ReadOps for TxRw<'_, T> { +impl<'tx, T: ReadOps> ReadOps for TxRw<'tx, T> { fn get(&self, map_id: DbMapId, key: &[u8]) -> crate::Result>> { self.deltas[map_id].get(key).map_or_else( || self.db.get(map_id, key), @@ -78,24 +78,24 @@ impl ReadOps for TxRw<'_, T> { ) } - fn prefix_iter( - &self, + fn prefix_iter<'a>( + &'a self, map_id: DbMapId, - prefix: Data, - ) -> crate::Result + '_> { - 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 + 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 + '_> { - 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 + 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)) } diff --git a/storage/core/src/backend.rs b/storage/core/src/backend.rs index ec9ed111d..292662de5 100644 --- a/storage/core/src/backend.rs +++ b/storage/core/src/backend.rs @@ -27,19 +27,25 @@ pub trait ReadOps { fn get(&self, map_id: DbMapId, key: &[u8]) -> crate::Result>>; /// 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 + '_>; + prefix: &[u8], + ) -> crate::Result + 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 + '_>; + key: &[u8], + ) -> crate::Result + use<'a, Self>>; } /// Write database operation diff --git a/storage/core/src/util.rs b/storage/core/src/util.rs index 076eca2a1..fa69649c0 100644 --- a/storage/core/src/util.rs +++ b/storage/core/src/util.rs @@ -49,12 +49,15 @@ pub struct MapPrefixIter<'m, T> { } impl<'m, T> MapPrefixIter<'m, T> { - pub fn new(map: &'m BTreeMap, prefix: Data) -> Self { + pub fn new(map: &'m BTreeMap, 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(), + } } } diff --git a/storage/failing/src/backend.rs b/storage/failing/src/backend.rs index 5bad381e9..e97b40742 100644 --- a/storage/failing/src/backend.rs +++ b/storage/failing/src/backend.rs @@ -188,24 +188,24 @@ impl backend::TxRw for TxRw<'_, T> { } } -impl 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>> { self.inner.get(map_id, key) } - fn prefix_iter( - &self, + fn prefix_iter<'a>( + &'a self, map_id: DbMapId, - prefix: Data, - ) -> storage_core::Result + '_> { + prefix: &[u8], + ) -> storage_core::Result + 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 + '_> { + key: &[u8], + ) -> storage_core::Result + use<'a, 'tx, T>> { self.inner.greater_equal_iter(map_id, key) } } diff --git a/storage/inmemory/src/lib.rs b/storage/inmemory/src/lib.rs index a823cee04..cf4750fce 100644 --- a/storage/inmemory/src/lib.rs +++ b/storage/inmemory/src/lib.rs @@ -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 + '_> { + prefix: &[u8], + ) -> storage_core::Result + 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 + '_> { - Ok(self.0[map_id].range(key..).map(|(k, v)| (k.clone(), v.clone()))) + key: &[u8], + ) -> storage_core::Result + use<'a>> { + Ok(self.0[map_id].range(key.to_vec()..).map(|(k, v)| (k.clone(), v.clone()))) } } diff --git a/storage/lmdb/src/lib.rs b/storage/lmdb/src/lib.rs index 59e7e11a1..217f00ed5 100644 --- a/storage/lmdb/src/lib.rs +++ b/storage/lmdb/src/lib.rs @@ -89,28 +89,28 @@ impl DbTx<'_, Tx> { } } -impl 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>> { 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 + '_> { - let iter = self.greater_equal_iter_impl(map_id, prefix.as_slice())?; - Ok(PrefixIter::new(iter, prefix)) + prefix: &[u8], + ) -> storage_core::Result + 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 + '_> { - let iter = self.greater_equal_iter_impl(map_id, key.as_slice())?.map(|result| { + key: &[u8], + ) -> storage_core::Result + 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()) }); diff --git a/storage/sqlite/src/lib.rs b/storage/sqlite/src/lib.rs index 8f63b095c..d0aa37d7f 100644 --- a/storage/sqlite/src/lib.rs +++ b/storage/sqlite/src/lib.rs @@ -141,7 +141,7 @@ impl Drop for DbTx<'_, IS_READONLY> { } } -impl 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>> { let conn_lock = self.lock_connection(); @@ -159,11 +159,11 @@ impl 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 + '_> { + prefix: &[u8], + ) -> storage_core::Result + 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(); @@ -186,11 +186,11 @@ impl 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 + '_> { + key: &[u8], + ) -> storage_core::Result + use<'a, 'tx, IS_READONLY>> { let conn_lock = self.lock_connection(); let mut stmt = conn_lock .connection diff --git a/storage/src/database/internal.rs b/storage/src/database/internal.rs index 92e58e288..e15922670 100644 --- a/storage/src/database/internal.rs +++ b/storage/src/database/internal.rs @@ -59,11 +59,11 @@ impl, DbMa { } -pub fn prefix_iter( - dbtx: &Tx, +pub fn prefix_iter<'tx, DbMap: schema::DbMap, Tx: ReadOps>( + dbtx: &'tx Tx, map_id: DbMapId, - prefix: Vec, -) -> crate::Result + '_> { + prefix: &'_ [u8], +) -> crate::Result + use<'tx, DbMap, Tx>> { dbtx.prefix_iter(map_id, prefix).map(|iter| { iter.map(|(k, v)| { ( @@ -74,20 +74,20 @@ pub fn prefix_iter( }) } -pub fn prefix_iter_keys( - dbtx: &Tx, +pub fn prefix_iter_keys<'tx, DbMap: schema::DbMap, Tx: ReadOps>( + dbtx: &'tx Tx, map_id: DbMapId, - prefix: Vec, -) -> crate::Result + '_> { + prefix: &'_ [u8], +) -> crate::Result + use<'tx, DbMap, Tx>> { dbtx.prefix_iter(map_id, prefix) .map(|iter| iter.map(|(k, _v)| Encoded::from_bytes_unchecked(k).decode())) } -pub fn greater_equal_iter( - dbtx: &Tx, +pub fn greater_equal_iter<'tx, DbMap: schema::DbMap, Tx: ReadOps>( + dbtx: &'tx Tx, map_id: DbMapId, - key: Vec, -) -> crate::Result + '_> { + key: &'_ [u8], +) -> crate::Result + use<'tx, DbMap, Tx>> { dbtx.greater_equal_iter(map_id, key).map(|iter| { iter.map(|(k, v)| { ( @@ -98,11 +98,11 @@ pub fn greater_equal_iter( }) } -pub fn greater_equal_iter_keys( - dbtx: &Tx, +pub fn greater_equal_iter_keys<'tx, DbMap: schema::DbMap, Tx: ReadOps>( + dbtx: &'tx Tx, map_id: DbMapId, - key: Vec, -) -> crate::Result + '_> { + key: &'_ [u8], +) -> crate::Result + use<'tx, DbMap, Tx>> { dbtx.greater_equal_iter(map_id, key) .map(|iter| iter.map(|(k, _v)| Encoded::from_bytes_unchecked(k).decode())) } diff --git a/storage/src/database/mod.rs b/storage/src/database/mod.rs index d7963fd96..d882c4a82 100644 --- a/storage/src/database/mod.rs +++ b/storage/src/database/mod.rs @@ -228,7 +228,8 @@ where Pfx: Encode, DbMap::Key: HasPrefix, { - internal::prefix_iter(self.dbtx, self.map_id, prefix.encode()) + let prefix = prefix.encode(); + internal::prefix_iter(self.dbtx, self.map_id, &prefix) } /// Iterator over keys starting with given prefix @@ -240,7 +241,8 @@ where Pfx: Encode, DbMap::Key: HasPrefix, { - internal::prefix_iter_keys::(self.dbtx, self.map_id, prefix.encode()) + let prefix = prefix.encode(); + internal::prefix_iter_keys::(self.dbtx, self.map_id, &prefix) } /// Iterator over decoded entries with key starting with given prefix @@ -268,7 +270,8 @@ where &self, key: &DbMap::Key, ) -> crate::Result + 'tx> { - internal::greater_equal_iter(self.dbtx, self.map_id, key.encode()) + let key = key.encode(); + internal::greater_equal_iter(self.dbtx, self.map_id, &key) } /// Same as `greater_equal_iter`, but only the keys are returned. @@ -276,7 +279,8 @@ where &self, key: &DbMap::Key, ) -> crate::Result + 'tx> { - internal::greater_equal_iter_keys::(self.dbtx, self.map_id, key.encode()) + let key = key.encode(); + internal::greater_equal_iter_keys::(self.dbtx, self.map_id, &key) } /// Same as `greater_equal_iter`, but already decoded valued are returned. @@ -325,7 +329,8 @@ where Pfx: Encode, DbMap::Key: HasPrefix, { - internal::prefix_iter(self.dbtx, self.map_id, prefix.encode()) + let prefix = prefix.encode(); + internal::prefix_iter(self.dbtx, self.map_id, &prefix) } } diff --git a/storage/src/database/raw.rs b/storage/src/database/raw.rs index d4bb9be99..f1d97ab7f 100644 --- a/storage/src/database/raw.rs +++ b/storage/src/database/raw.rs @@ -135,7 +135,7 @@ pub fn dump_storage( .enumerate() .map(|(idx, _dbinfo)| { let idx = storage_core::DbMapId::new(idx); - let items = dbtx.dbtx.prefix_iter(idx, Vec::new())?; + let items = dbtx.dbtx.prefix_iter(idx, &[])?; Ok((DbMapId::from_idx_unchecked(idx), items.collect())) }) .collect::>>()