From 8547fbfaedec342116ff05effc194120ee35346a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s?= <47506558+MegaRedHand@users.noreply.github.com> Date: Thu, 16 Feb 2023 17:25:21 -0300 Subject: [PATCH] test: `walk_back` and `walk_range` (#1407) Co-authored-by: lambdaclass-user --- .../db/src/implementation/mdbx/cursor.rs | 25 +++---- .../storage/db/src/implementation/mdbx/mod.rs | 75 ++++++++++++++++++- 2 files changed, 85 insertions(+), 15 deletions(-) diff --git a/crates/storage/db/src/implementation/mdbx/cursor.rs b/crates/storage/db/src/implementation/mdbx/cursor.rs index ed8b1bbe6a..cce188f841 100644 --- a/crates/storage/db/src/implementation/mdbx/cursor.rs +++ b/crates/storage/db/src/implementation/mdbx/cursor.rs @@ -100,13 +100,14 @@ impl<'tx, K: TransactionKind, T: Table> DbCursorRO<'tx, T> for Cursor<'tx, K, T> Self: Sized, { let start = match range.start_bound().cloned() { - Bound::Included(key) => self.inner.set_range(key.encode().as_ref()), - Bound::Excluded(key) => { - self.inner - .set_range(key.encode().as_ref()) - .map_err(|e| Error::Read(e.into()))? - .map(decoder::); - self.inner.next() + Bound::Included(key) => { + if matches!(range.end_bound().cloned(), Bound::Included(end_key) | Bound::Excluded(end_key) if end_key < key) { + return Err(Error::Read(2)) + } + self.inner.set_range(key.encode().as_ref()) + } + Bound::Excluded(_key) => { + unreachable!("Rust doesn't allow for Bound::Excluded in starting bounds"); } Bound::Unbounded => self.inner.first(), } @@ -124,13 +125,11 @@ impl<'tx, K: TransactionKind, T: Table> DbCursorRO<'tx, T> for Cursor<'tx, K, T> Self: Sized, { let start = if let Some(start_key) = start_key { - self.inner - .set_range(start_key.encode().as_ref()) - .map_err(|e| Error::Read(e.into()))? - .map(decoder::) + decode!(self.inner.set_range(start_key.encode().as_ref())) } else { - self.last().transpose() - }; + self.last() + } + .transpose(); Ok(ReverseWalker::new(self, start)) } diff --git a/crates/storage/db/src/implementation/mdbx/mod.rs b/crates/storage/db/src/implementation/mdbx/mod.rs index fc76e9a76b..c252ce7bda 100644 --- a/crates/storage/db/src/implementation/mdbx/mod.rs +++ b/crates/storage/db/src/implementation/mdbx/mod.rs @@ -110,9 +110,8 @@ impl Deref for Env { /// Collection of database test utilities #[cfg(any(test, feature = "test-utils"))] pub mod test_utils { + use super::*; use reth_libmdbx::WriteMap; - - use super::{Env, EnvKind, EnvironmentKind, Path}; use std::sync::Arc; /// Error during database creation @@ -269,6 +268,39 @@ mod tests { assert_eq!(walker.next(), Some(Ok((2, H256::zero())))); // next() returns None after walker is done assert_eq!(walker.next(), None); + + // (∞, ∞) + let mut walker = cursor.walk_range(..).unwrap(); + assert_eq!(walker.next(), Some(Ok((0, H256::zero())))); + assert_eq!(walker.next(), Some(Ok((1, H256::zero())))); + assert_eq!(walker.next(), Some(Ok((2, H256::zero())))); + assert_eq!(walker.next(), Some(Ok((3, H256::zero())))); + // next() returns None after walker is done + assert_eq!(walker.next(), None); + } + + #[test] + fn db_cursor_walk_range_invalid() { + let db: Arc> = test_utils::create_test_db(EnvKind::RW); + + // PUT (0, 0), (1, 0), (2, 0), (3, 0) + let tx = db.tx_mut().expect(ERROR_INIT_TX); + vec![0, 1, 2, 3] + .into_iter() + .try_for_each(|key| tx.put::(key, H256::zero())) + .expect(ERROR_PUT); + tx.commit().expect(ERROR_COMMIT); + + let tx = db.tx().expect(ERROR_INIT_TX); + let mut cursor = tx.cursor_read::().unwrap(); + + // start bound greater than end bound + let res = cursor.walk_range(3..1); + assert!(matches!(res, Err(Error::Read(2)))); + + // start bound greater than end bound + let res = cursor.walk_range(15..=2); + assert!(matches!(res, Err(Error::Read(2)))); } #[test] @@ -331,6 +363,45 @@ mod tests { assert_eq!(walker.next(), None); } + #[test] + fn db_walk_back() { + let db: Arc> = test_utils::create_test_db(EnvKind::RW); + + // PUT (0, 0), (1, 0), (3, 0) + let tx = db.tx_mut().expect(ERROR_INIT_TX); + vec![0, 1, 3] + .into_iter() + .try_for_each(|key| tx.put::(key, H256::zero())) + .expect(ERROR_PUT); + tx.commit().expect(ERROR_COMMIT); + + let tx = db.tx().expect(ERROR_INIT_TX); + let mut cursor = tx.cursor_read::().unwrap(); + + let mut reverse_walker = cursor.walk_back(Some(1)).unwrap(); + assert_eq!(reverse_walker.next(), Some(Ok((1, H256::zero())))); + assert_eq!(reverse_walker.next(), Some(Ok((0, H256::zero())))); + assert_eq!(reverse_walker.next(), None); + + let mut reverse_walker = cursor.walk_back(Some(2)).unwrap(); + assert_eq!(reverse_walker.next(), Some(Ok((3, H256::zero())))); + assert_eq!(reverse_walker.next(), Some(Ok((1, H256::zero())))); + assert_eq!(reverse_walker.next(), Some(Ok((0, H256::zero())))); + assert_eq!(reverse_walker.next(), None); + + let mut reverse_walker = cursor.walk_back(Some(4)).unwrap(); + assert_eq!(reverse_walker.next(), Some(Ok((3, H256::zero())))); + assert_eq!(reverse_walker.next(), Some(Ok((1, H256::zero())))); + assert_eq!(reverse_walker.next(), Some(Ok((0, H256::zero())))); + assert_eq!(reverse_walker.next(), None); + + let mut reverse_walker = cursor.walk_back(None).unwrap(); + assert_eq!(reverse_walker.next(), Some(Ok((3, H256::zero())))); + assert_eq!(reverse_walker.next(), Some(Ok((1, H256::zero())))); + assert_eq!(reverse_walker.next(), Some(Ok((0, H256::zero())))); + assert_eq!(reverse_walker.next(), None); + } + #[test] fn db_cursor_seek_exact_or_previous_key() { let db: Arc> = test_utils::create_test_db(EnvKind::RW);