diff --git a/rust-bins/duniter-dbex/src/migrate.rs b/rust-bins/duniter-dbex/src/migrate.rs index b4bcc7abf868780453ad8a1921a1f7191d75a7df..1678bdeb23a12696d7fa533031656ba16225edcf 100644 --- a/rust-bins/duniter-dbex/src/migrate.rs +++ b/rust-bins/duniter-dbex/src/migrate.rs @@ -160,11 +160,8 @@ fn migrate_inner( } fn get_target_block_number(duniter_js_db: &BcV1Db<LevelDb>) -> KvResult<Option<BlockNumber>> { - duniter_js_db.main_blocks().iter(.., |it| { - it.reverse() - .keys() - .map(|k_res| k_res.map(|bn| bn.0)) - .next_res() + duniter_js_db.main_blocks().iter_rev(.., |it| { + it.keys().map(|k_res| k_res.map(|bn| bn.0)).next_res() }) } diff --git a/rust-libs/duniter-dbs-read-ops/src/lib.rs b/rust-libs/duniter-dbs-read-ops/src/lib.rs index 80708700004a97d486744ded469f0505a759ebe0..c123d2671b5a199c7433beeae4cba064874fa8a6 100644 --- a/rust-libs/duniter-dbs-read-ops/src/lib.rs +++ b/rust-libs/duniter-dbs-read-ops/src/lib.rs @@ -29,7 +29,7 @@ use duniter_dbs::{kv_typed::prelude::*, BlockMetaV2}; pub fn get_current_block_meta<BcDb: BcV2DbReadable>(bc_db: &BcDb) -> KvResult<Option<BlockMetaV2>> { bc_db .blocks_meta() - .iter(.., |it| it.reverse().values().next_res()) + .iter_rev(.., |it| it.values().next_res()) } pub fn tx_exist<BcDb: BcV2DbReadable>(bc_db_ro: &BcDb, hash: Hash) -> KvResult<bool> { diff --git a/rust-libs/duniter-dbs-write-ops/src/bc/uds.rs b/rust-libs/duniter-dbs-write-ops/src/bc/uds.rs index a99d20a4f330bd9c691e18bc95c1e62b88fc2c31..2dde737f962df4b644ff0a1efa704358f947e935 100644 --- a/rust-libs/duniter-dbs-write-ops/src/bc/uds.rs +++ b/rust-libs/duniter-dbs-write-ops/src/bc/uds.rs @@ -27,7 +27,7 @@ pub(crate) fn create_uds<B: Backend>( uds_reval: &mut TxColRw<B::Col, UdsRevalEvent>, ) -> KvResult<()> { let previous_ud_amount = uds_reval - .iter(.., |it| it.reverse().values().next_res())? + .iter_rev(.., |it| it.values().next_res())? .unwrap_or(SourceAmountValV2(SourceAmount::ZERO)); if dividend > previous_ud_amount.0 { uds_reval.upsert(U32BE(block_number.0), SourceAmountValV2(dividend)); @@ -50,7 +50,7 @@ pub(crate) fn revert_uds<B: Backend>( uds_reval: &mut TxColRw<B::Col, UdsRevalEvent>, ) -> KvResult<()> { let previous_reval_block_number = uds_reval - .iter(.., |it| it.reverse().keys().next_res())? + .iter_rev(.., |it| it.keys().next_res())? .expect("corrupted db") .0; if block_number.0 == previous_reval_block_number { diff --git a/rust-libs/duniter-dbs/Cargo.toml b/rust-libs/duniter-dbs/Cargo.toml index ae7fe8124f0a866dc0e6f4496f648bc8f3af07d7..30d02d51960137ac0f31bec862de1cc46d351031 100644 --- a/rust-libs/duniter-dbs/Cargo.toml +++ b/rust-libs/duniter-dbs/Cargo.toml @@ -34,7 +34,8 @@ tempdir = "0.3.7" unwrap = "1.2.1" [features] -default = ["sled_backend"] +#default = ["sled_backend"] +default = ["sled_backend", "explorer", "leveldb_backend"] explorer = ["chrono", "kv_typed/explorer"] leveldb_backend = ["kv_typed/leveldb_backend"] diff --git a/rust-libs/duniter-dbs/tests/test_read_write.rs b/rust-libs/duniter-dbs/tests/test_read_write.rs index a878ab2c17f79f794d11d1f7a84065145b9e3e18..b1af6b37b5391ab65a12597d59a07b1febaab819 100644 --- a/rust-libs/duniter-dbs/tests/test_read_write.rs +++ b/rust-libs/duniter-dbs/tests/test_read_write.rs @@ -247,26 +247,21 @@ fn write_some_entries_and_iter<B: Backend>(db: &BcV1Db<B>) -> KvResult<()> { Ok::<(), KvError>(()) })?; - uids_reader.iter(k2.., |entries_iter| { - let mut entries_iter_rev = entries_iter.reverse(); - + uids_reader.iter_rev(k2.., |mut entries_iter_rev| { assert_eq!(Some((k3, p3)), entries_iter_rev.next_res()?); assert_eq!(Some((k2, p2)), entries_iter_rev.next_res()?); assert_eq!(None, entries_iter_rev.next_res()?); Ok::<(), KvError>(()) })?; - uids_reader.iter(..=k2, |entries_iter| { - let mut entries_iter_rev = entries_iter.reverse(); - + uids_reader.iter_rev(..=k2, |mut entries_iter_rev| { assert_eq!(Some((k2, p2)), entries_iter_rev.next_res()?); assert_eq!(Some((k1, p1)), entries_iter_rev.next_res()?); Ok::<(), KvError>(()) })?; - uids_reader.iter(..=k2, |it| { - let mut keys_iter_rev = it.keys().reverse(); - + uids_reader.iter_rev(..=k2, |iter_rev| { + let mut keys_iter_rev = iter_rev.keys(); assert_eq!(Some(k2), keys_iter_rev.next_res()?); assert_eq!(Some(k1), keys_iter_rev.next_res()?); assert_eq!(None, keys_iter_rev.next_res()?); diff --git a/rust-libs/modules/gva/dbs-reader/src/lib.rs b/rust-libs/modules/gva/dbs-reader/src/lib.rs index e722fa3e845b3c2a3dd275f48be0beee54d1b3a1..99676f7053dcd10620d32f117a4d8b0c3fbee39c 100644 --- a/rust-libs/modules/gva/dbs-reader/src/lib.rs +++ b/rust-libs/modules/gva/dbs-reader/src/lib.rs @@ -73,7 +73,7 @@ impl DbsReader { ) -> KvResult<Option<SourceAmount>> { bc_db .uds_reval() - .iter(.., |it| it.reverse().values().map_ok(|v| v.0).next_res()) + .iter_rev(.., |it| it.values().map_ok(|v| v.0).next_res()) } pub fn get_blockchain_time(&self, block_number: BlockNumber) -> anyhow::Result<u64> { diff --git a/rust-libs/modules/gva/dbs-reader/src/uds_of_pubkey.rs b/rust-libs/modules/gva/dbs-reader/src/uds_of_pubkey.rs index d54f04e65f2e12671fb9fd88f8b9ae9c7927bdc3..1033e720681c6a086941f5ff35e730f44a0c8316 100644 --- a/rust-libs/modules/gva/dbs-reader/src/uds_of_pubkey.rs +++ b/rust-libs/modules/gva/dbs-reader/src/uds_of_pubkey.rs @@ -54,12 +54,12 @@ impl DbsReader { }) } else { let last_ud_opt = - blocks_with_ud.iter(.., |it| it.keys().reverse().next_res())?; - blocks_with_ud.iter(.., move |it| { + blocks_with_ud.iter_rev(.., |it| it.keys().next_res())?; + blocks_with_ud.iter_rev(.., move |it| { all_uds_of_pubkey_inner::<FileBackend, _>( gva_idty, page_info, - it.keys().reverse().map_ok(|bn| BlockNumber(bn.0)), + it.keys().map_ok(|bn| BlockNumber(bn.0)), uds_reval, last_ud_opt.map(|bn| BlockNumber(bn.0)), ) @@ -79,12 +79,12 @@ impl DbsReader { }) } else { let last_ud_opt = - blocks_with_ud.iter(.., |it| it.keys().reverse().next_res())?; - blocks_with_ud.iter(..=U32BE(pos.0), move |it| { + blocks_with_ud.iter_rev(.., |it| it.keys().next_res())?; + blocks_with_ud.iter_rev(..=U32BE(pos.0), move |it| { all_uds_of_pubkey_inner::<FileBackend, _>( gva_idty, page_info, - it.keys().reverse().map_ok(|bn| BlockNumber(bn.0)), + it.keys().map_ok(|bn| BlockNumber(bn.0)), uds_reval, last_ud_opt.map(|bn| BlockNumber(bn.0)), ) @@ -127,8 +127,8 @@ impl DbsReader { }, )? } else { - uds.iter(UdIdV2(pubkey, BlockNumber(0))..=UdIdV2(pubkey, pos), |it| { - let it = it.keys().reverse().map_ok(|UdIdV2(_p, bn)| bn); + uds.iter_rev(UdIdV2(pubkey, BlockNumber(0))..=UdIdV2(pubkey, pos), |it| { + let it = it.keys().map_ok(|UdIdV2(_p, bn)| bn); if let Some(bn_to_exclude) = bn_to_exclude_opt { it.filter_ok(|bn| !bn_to_exclude.contains(&bn)) .collect::<KvResult<Vec<_>>>() @@ -151,10 +151,10 @@ impl DbsReader { }, )? } else { - uds.iter( + uds.iter_rev( UdIdV2(pubkey, BlockNumber(0))..UdIdV2(pubkey, BlockNumber(u32::MAX)), |it| { - let it = it.keys().reverse().map_ok(|UdIdV2(_p, bn)| bn); + let it = it.keys().map_ok(|UdIdV2(_p, bn)| bn); if let Some(bn_to_exclude) = bn_to_exclude_opt { it.filter_ok(|bn| !bn_to_exclude.contains(&bn)) .collect::<KvResult<Vec<_>>>() @@ -177,9 +177,7 @@ impl DbsReader { blocks_numbers[blocks_numbers.len() - 1] }; let first_reval = uds_reval - .iter(..=U32BE(first_block_number.0), |it| { - it.reverse().keys().next_res() - })? + .iter_rev(..=U32BE(first_block_number.0), |it| it.keys().next_res())? .expect("corrupted db"); let blocks_numbers_len = blocks_numbers.len(); let blocks_numbers = blocks_numbers.into_iter(); @@ -263,9 +261,7 @@ where }; let first_reval = uds_reval - .iter(..=U32BE(first_block_number.0), |it| { - it.reverse().keys().next_res() - })? + .iter_rev(..=U32BE(first_block_number.0), |it| it.keys().next_res())? .expect("corrupted db"); let uds_with_sum = if page_info.order { @@ -377,21 +373,25 @@ fn get_first_and_last_unspent_ud<BC: BackendCol>( bn_to_exclude_opt: Option<&BTreeSet<BlockNumber>>, ) -> KvResult<(Option<BlockNumber>, Option<BlockNumber>)> { if let Some(bn_to_exclude) = bn_to_exclude_opt { - uds.iter( - UdIdV2(pubkey, BlockNumber(0))..UdIdV2(pubkey, BlockNumber(u32::MAX)), - |it| { - let mut it = it.keys(); - Ok(( - loop { - if let Some(UdIdV2(_p, bn)) = it.next_res()? { + Ok(( + uds.iter( + UdIdV2(pubkey, BlockNumber(0))..UdIdV2(pubkey, BlockNumber(u32::MAX)), + |it| { + it.keys() + .filter_map_ok(|UdIdV2(_p, bn)| { if !bn_to_exclude.contains(&bn) { - break Some(bn); + Some(bn) + } else { + None } - } else { - break None; - } - }, - it.reverse() + }) + .next_res() + }, + )?, + uds.iter_rev( + UdIdV2(pubkey, BlockNumber(0))..UdIdV2(pubkey, BlockNumber(u32::MAX)), + |it| { + it.keys() .filter_map_ok(|UdIdV2(_p, bn)| { if !bn_to_exclude.contains(&bn) { Some(bn) @@ -399,21 +399,21 @@ fn get_first_and_last_unspent_ud<BC: BackendCol>( None } }) - .next_res()?, - )) - }, - ) + .next_res() + }, + )?, + )) } else { - uds.iter( - UdIdV2(pubkey, BlockNumber(0))..UdIdV2(pubkey, BlockNumber(u32::MAX)), - |it| { - let mut it = it.keys(); - Ok(( - it.next_res()?.map(|UdIdV2(_p, bn)| bn), - it.reverse().next_res()?.map(|UdIdV2(_p, bn)| bn), - )) - }, - ) + Ok(( + uds.iter( + UdIdV2(pubkey, BlockNumber(0))..UdIdV2(pubkey, BlockNumber(u32::MAX)), + |it| it.keys().map_ok(|UdIdV2(_p, bn)| bn).next_res(), + )?, + uds.iter_rev( + UdIdV2(pubkey, BlockNumber(0))..UdIdV2(pubkey, BlockNumber(u32::MAX)), + |it| it.keys().map_ok(|UdIdV2(_p, bn)| bn).next_res(), + )?, + )) } } diff --git a/rust-libs/modules/gva/dbs-reader/src/utxos.rs b/rust-libs/modules/gva/dbs-reader/src/utxos.rs index bd1510179856896131db693b8e37aebe9a0832cb..7f316c243f24e430949e1728aa9c759b9f9eee26 100644 --- a/rust-libs/modules/gva/dbs-reader/src/utxos.rs +++ b/rust-libs/modules/gva/dbs-reader/src/utxos.rs @@ -106,8 +106,8 @@ impl DbsReader { let last_cursor_opt = if page_info.not_all() { self.0 .gva_utxos() - .iter(k_min..k_max, |it| { - it.keys().reverse().filter_map(mempool_filter).next_res() + .iter_rev(k_min..k_max, |it| { + it.keys().filter_map(mempool_filter).next_res() })? .map(|gva_utxo_id| UtxoCursor { block_number: BlockNumber(gva_utxo_id.get_block_number()), @@ -134,9 +134,17 @@ impl DbsReader { ); } } - let mut sum = SourceAmount::ZERO; + let UtxosWithSum { utxos, mut sum } = if page_info.order { + self.0.gva_utxos().iter(k_min..k_max, |it| { + find_script_utxos_inner(txs_mp_db_ro, amount_target_opt, page_info, it) + })? + } else { + self.0.gva_utxos().iter_rev(k_min..k_max, |it| { + find_script_utxos_inner(txs_mp_db_ro, amount_target_opt, page_info, it) + })? + }; - let utxos = self.0.gva_utxos().iter(k_min..k_max, |mut it| { + /* let utxos = self.0.gva_utxos().iter(k_min..k_max, |mut it| { if !page_info.order { it = it.reverse(); } @@ -196,42 +204,7 @@ impl DbsReader { } else { it.collect::<KvResult<Vec<_>>>() } - /*let mut utxos = Vec::new(); - for entry_res in it { - let (gva_utxo_id, SourceAmountValV2(utxo_amount)) = entry_res?; - let tx_hash = gva_utxo_id.get_tx_hash(); - let output_index = gva_utxo_id.get_output_index() as u32; - if !txs_mp_db_ro - .utxos_ids() - .contains_key(&UtxoIdDbV2(tx_hash, output_index))? - { - utxos.push(( - gva_db_ro - .blockchain_time() - .get(&U32BE(gva_utxo_id.get_block_number()))? - .ok_or_else(|| { - KvError::DbCorrupted(format!( - "No gva time for block {}", - gva_utxo_id.get_block_number() - )) - })? as i64, - UtxoIdV10 { - tx_hash, - output_index: output_index as usize, - }, - utxo_amount, - )); - - total = total + utxo_amount; - if let Some(total_target) = amount_target_opt { - if total >= total_target { - return Ok((utxos, total)); - } - } - } - } - Ok::<_, KvError>((utxos, total))*/ - })?; + })?;*/ if amount_target_opt.is_none() { sum = utxos.iter().map(|(_utxo_id_with_bn, sa)| *sa).sum(); @@ -257,6 +230,78 @@ impl DbsReader { } } +fn find_script_utxos_inner<TxsMpDb, I>( + txs_mp_db_ro: &TxsMpDb, + amount_target_opt: Option<SourceAmount>, + page_info: PageInfo<UtxoCursor>, + utxos_iter: I, +) -> KvResult<UtxosWithSum> +where + TxsMpDb: TxsMpV2DbReadable, + I: Iterator<Item = KvResult<(GvaUtxoIdDbV1, SourceAmountValV2)>>, +{ + let mut sum = SourceAmount::ZERO; + + let it = utxos_iter.filter_map(|entry_res| match entry_res { + Ok((gva_utxo_id, SourceAmountValV2(utxo_amount))) => { + let tx_hash = gva_utxo_id.get_tx_hash(); + let output_index = gva_utxo_id.get_output_index(); + match txs_mp_db_ro + .utxos_ids() + .contains_key(&UtxoIdDbV2(tx_hash, output_index as u32)) + { + Ok(false) => Some(Ok(( + UtxoCursor { + tx_hash, + output_index, + block_number: BlockNumber(gva_utxo_id.get_block_number()), + }, + utxo_amount, + ))), + Ok(true) => None, + Err(e) => Some(Err(e)), + } + } + Err(e) => Some(Err(e)), + }); + let utxos = if let Some(limit) = page_info.limit_opt { + if let Some(total_target) = amount_target_opt { + it.take(limit) + .take_while(|res| match res { + Ok((_, utxo_amount)) => { + if sum < total_target { + sum = sum + *utxo_amount; + true + } else { + false + } + } + Err(_) => true, + }) + .collect::<KvResult<Vec<_>>>()? + } else { + it.take(limit).collect::<KvResult<Vec<_>>>()? + } + } else if let Some(total_target) = amount_target_opt { + it.take_while(|res| match res { + Ok((_, utxo_amount)) => { + if sum < total_target { + sum = sum + *utxo_amount; + true + } else { + false + } + } + Err(_) => true, + }) + .collect::<KvResult<Vec<_>>>()? + } else { + it.collect::<KvResult<Vec<_>>>()? + }; + + Ok(UtxosWithSum { utxos, sum }) +} + #[cfg(test)] mod tests { diff --git a/rust-libs/tools/kv_typed/src/backend.rs b/rust-libs/tools/kv_typed/src/backend.rs index bafc69ab76aaed2f173a2ea24db82848ff9ab8aa..6e8688c93c09e3099d6ce2d2d07d9a02ea7ea444 100644 --- a/rust-libs/tools/kv_typed/src/backend.rs +++ b/rust-libs/tools/kv_typed/src/backend.rs @@ -58,6 +58,7 @@ pub trait BackendCol: 'static + Clone + Debug + Send + Sync { fn contains_key<K: Key>(&self, k: &K) -> KvResult<bool>; fn count(&self) -> KvResult<usize>; fn iter<K: Key, V: Value>(&self, range: RangeBytes) -> Self::Iter; + fn iter_rev<K: Key, V: Value>(&self, range: RangeBytes) -> Self::Iter; fn put<K: Key, V: Value>(&mut self, k: &K, value: &V) -> KvResult<()>; fn delete<K: Key>(&mut self, k: &K) -> KvResult<()>; fn new_batch() -> Self::Batch; diff --git a/rust-libs/tools/kv_typed/src/backend/leveldb.rs b/rust-libs/tools/kv_typed/src/backend/leveldb.rs index b03a712223fd9601d051c1a377c7c972deb5bdf9..7176a7fddffc71fcfac14165bcf8f2ae74201b9b 100644 --- a/rust-libs/tools/kv_typed/src/backend/leveldb.rs +++ b/rust-libs/tools/kv_typed/src/backend/leveldb.rs @@ -210,6 +210,10 @@ impl BackendCol for LevelDbCol { LevelDbIter(self.0.iter(ReadOptions::new())) } #[inline(always)] + fn iter_rev<K: Key, V: Value>(&self, _range: RangeBytes) -> Self::Iter { + LevelDbIter(self.0.iter(ReadOptions::new()).reverse()) + } + #[inline(always)] fn save(&self) -> KvResult<()> { Ok(()) } diff --git a/rust-libs/tools/kv_typed/src/backend/memory.rs b/rust-libs/tools/kv_typed/src/backend/memory.rs index fd3709c5c59eab6c3b1f59155c34ca701d075525..b3ec5589cae81679324b4bf4e341a59040f1d695 100644 --- a/rust-libs/tools/kv_typed/src/backend/memory.rs +++ b/rust-libs/tools/kv_typed/src/backend/memory.rs @@ -337,6 +337,10 @@ impl BackendCol for MemCol { }) } #[inline(always)] + fn iter_rev<K: Key, V: Value>(&self, range: RangeBytes) -> Self::Iter { + self.iter::<K, V>(range).reverse() + } + #[inline(always)] fn save(&self) -> KvResult<()> { /*if let Some(ref file_path) = self.path { let bytes = Self::tree_to_bytes(&self.tree); diff --git a/rust-libs/tools/kv_typed/src/backend/memory_singleton.rs b/rust-libs/tools/kv_typed/src/backend/memory_singleton.rs index d77bcedda42b506b4861a5587fec26312038a3ea..200973d752061dd568183fd666e62c57d35a45f5 100644 --- a/rust-libs/tools/kv_typed/src/backend/memory_singleton.rs +++ b/rust-libs/tools/kv_typed/src/backend/memory_singleton.rs @@ -155,6 +155,10 @@ impl BackendCol for MemCol { MemIter(self.0.clone()) } #[inline(always)] + fn iter_rev<K: Key, V: Value>(&self, _: RangeBytes) -> Self::Iter { + MemIter(self.0.clone()) + } + #[inline(always)] fn save(&self) -> KvResult<()> { Ok(()) } diff --git a/rust-libs/tools/kv_typed/src/backend/sled.rs b/rust-libs/tools/kv_typed/src/backend/sled.rs index 6efd6cb2144035c5896afa99120005d8c45ea14c..d519fa0027192b23992bd233f6cf298fa1ec04f8 100644 --- a/rust-libs/tools/kv_typed/src/backend/sled.rs +++ b/rust-libs/tools/kv_typed/src/backend/sled.rs @@ -163,6 +163,10 @@ impl BackendCol for SledCol { } } #[inline(always)] + fn iter_rev<K: Key, V: Value>(&self, range: RangeBytes) -> Self::Iter { + self.iter::<K, V>(range).reverse() + } + #[inline(always)] fn save(&self) -> KvResult<()> { self.0.flush()?; Ok(()) diff --git a/rust-libs/tools/kv_typed/src/collection_ro.rs b/rust-libs/tools/kv_typed/src/collection_ro.rs index 8096e05e5b6867e656d39cb861f27545bc40ba77..485b204f6445616c67f7779a78a38ccd16caad41 100644 --- a/rust-libs/tools/kv_typed/src/collection_ro.rs +++ b/rust-libs/tools/kv_typed/src/collection_ro.rs @@ -28,6 +28,25 @@ pub trait DbCollectionRo: Sized { range: R, f: F, ) -> D; + /// Don't worry about complex iter type. Use it like an `impl Iterator<Item=KvResult<(K, V)>>`. + fn iter_rev< + D: Send + Sync, + R: 'static + RangeBounds<Self::K>, + F: FnOnce( + KvIter< + Self::BackendCol, + <Self::BackendCol as BackendCol>::KeyBytes, + <Self::BackendCol as BackendCol>::ValueBytes, + <Self::BackendCol as BackendCol>::Iter, + Self::K, + Self::V, + >, + ) -> D, + >( + &self, + range: R, + f: F, + ) -> D; fn subscribe(&self, subscriber_sender: Subscriber<Self::Event>) -> KvResult<()>; } @@ -108,6 +127,30 @@ impl<BC: BackendCol, E: EventTrait> DbCollectionRo for ColRo<BC, E> { f(KvIter::new(iter, range)) } #[inline(always)] + fn iter_rev< + D: Send + Sync, + R: 'static + RangeBounds<Self::K>, + F: FnOnce( + KvIter< + Self::BackendCol, + <Self::BackendCol as BackendCol>::KeyBytes, + <Self::BackendCol as BackendCol>::ValueBytes, + <Self::BackendCol as BackendCol>::Iter, + Self::K, + Self::V, + >, + ) -> D, + >( + &self, + range: R, + f: F, + ) -> D { + let range: RangeBytes = crate::iter::convert_range::<Self::K, R>(range); + let r = self.inner.read(); + let iter = r.backend_col.iter::<Self::K, Self::V>(range.clone()); + f(KvIter::new(iter, range).reverse()) + } + #[inline(always)] fn subscribe(&self, subscriber_sender: Subscriber<Self::Event>) -> KvResult<()> { self.subscription_sender .try_send(subscriber_sender) diff --git a/rust-libs/tools/kv_typed/src/explorer.rs b/rust-libs/tools/kv_typed/src/explorer.rs index 5a86fa1daa87ced1f3ebc780b06e362f0e1e898f..1d5926db8351da880a59589e8fe46314896b2476 100644 --- a/rust-libs/tools/kv_typed/src/explorer.rs +++ b/rust-libs/tools/kv_typed/src/explorer.rs @@ -365,20 +365,21 @@ impl<'a> ExplorerAction<'a> { }; if let Some(limit) = limit { - col.iter(range, |iter| { - if reverse { - iter.reverse() - .step_by(step.get()) + if reverse { + col.iter_rev(range, |iter| { + iter.step_by(step.get()) .filter_map(filter_map_closure) .take(limit) .collect() - } else { + }) + } else { + col.iter(range, |iter| { iter.step_by(step.get()) .filter_map(filter_map_closure) .take(limit) .collect() - } - }) + }) + } } else { { let (send, recv) = unbounded(); @@ -389,24 +390,29 @@ impl<'a> ExplorerAction<'a> { iter.filter_map(filter_map_closure).collect() }); - col.iter(range, |iter| { - if reverse { - for entry_res in iter.reverse() { + if reverse { + col.iter_rev(range, |iter| { + for entry_res in iter { if send.try_send(entry_res).is_err() { return handler.join().expect("child thread panic"); } } - } else { + drop(send); + + handler.join().expect("child thread panic") + }) + } else { + col.iter(range, |iter| { for entry_res in iter { if send.try_send(entry_res).is_err() { return handler.join().expect("child thread panic"); } } - } - drop(send); + drop(send); - handler.join().expect("child thread panic") - }) + handler.join().expect("child thread panic") + }) + } } } } diff --git a/rust-libs/tools/kv_typed/src/lib.rs b/rust-libs/tools/kv_typed/src/lib.rs index 0908acaaa0c563be45bfa0eed80b50fafc676edd..2a881c6b7e68ea2559c2c4e7fb7ec518d8286767 100644 --- a/rust-libs/tools/kv_typed/src/lib.rs +++ b/rust-libs/tools/kv_typed/src/lib.rs @@ -79,9 +79,7 @@ pub mod prelude { #[cfg(feature = "explorer")] pub use crate::explorer::{ExplorableKey, ExplorableValue}; pub use crate::from_bytes::FromBytes; - pub use crate::iter::{ - keys::KvIterKeys, values::KvIterValues, EntryIter, KvIter, ResultIter, ReversableIterator, - }; + pub use crate::iter::{keys::KvIterKeys, values::KvIterValues, EntryIter, KvIter, ResultIter}; pub use crate::key::{Key, U32BE}; pub use crate::subscription::{NewSubscribers, Subscriber, Subscribers}; pub use crate::transactional_read::{TransactionalRead, TxColRo}; @@ -97,7 +95,7 @@ pub(crate) use crate::collection_inner::ColInner; pub(crate) use crate::error::BackendResult; #[cfg(feature = "explorer")] pub(crate) use crate::explorer::{ExplorableKey, ExplorableValue}; -pub(crate) use crate::iter::RangeBytes; +pub(crate) use crate::iter::{RangeBytes, ReversableIterator}; pub(crate) use crate::prelude::*; pub(crate) use crate::subscription::{ColSubscribers, SubscriptionsSender}; pub(crate) use crate::transactional_write::tx_iter::BackendTxIter; diff --git a/rust-libs/tools/kv_typed/src/transactional_read.rs b/rust-libs/tools/kv_typed/src/transactional_read.rs index e4ef0b077fab0b5e0e8290292fb6497daa64a451..94b63d4606815d5b18d35e95990a069265a006c5 100644 --- a/rust-libs/tools/kv_typed/src/transactional_read.rs +++ b/rust-libs/tools/kv_typed/src/transactional_read.rs @@ -57,6 +57,22 @@ impl<'db, BC: BackendCol, E: EventTrait> TxColRo<'db, BC, E> { .iter::<E::K, E::V>(range_bytes.clone()); f(KvIter::new(backend_iter, range_bytes)) } + #[allow(clippy::type_complexity)] + #[inline(always)] + /// Don't worry about complex iter type. Use it like an `impl Iterator<Item=KvResult<(K, V)>>`. + pub fn iter_rev<D, R, F>(&self, range: R, f: F) -> D + where + D: Send + Sync, + R: 'static + RangeBounds<E::K>, + F: FnOnce(KvIter<BC, BC::KeyBytes, BC::ValueBytes, BC::Iter, E::K, E::V>) -> D, + { + let range_bytes = crate::iter::convert_range::<E::K, R>(range); + let backend_iter = self + .col_reader + .backend_col + .iter::<E::K, E::V>(range_bytes.clone()); + f(KvIter::new(backend_iter, range_bytes).reverse()) + } } impl<'db, V: ValueZc, BC: BackendCol, E: EventTrait<V = V>> TxColRo<'db, BC, E> { pub fn get_ref<D, F: Fn(&V::Ref) -> KvResult<D>>(&self, k: &E::K, f: F) -> KvResult<Option<D>> { diff --git a/rust-libs/tools/kv_typed/src/transactional_write.rs b/rust-libs/tools/kv_typed/src/transactional_write.rs index 64b522788bdeecc4051f1464eabaf93771c3dfff..b7b4d4181871230679d6a3122a313debca46f75e 100644 --- a/rust-libs/tools/kv_typed/src/transactional_write.rs +++ b/rust-libs/tools/kv_typed/src/transactional_write.rs @@ -98,6 +98,35 @@ impl<'db, BC: BackendCol, E: EventTrait> TxColRw<'db, BC, E> { range_bytes, )) } + #[allow(clippy::type_complexity)] + #[inline(always)] + /// Don't worry about complex iter type. Use it like an `impl Iterator<Item=KvResult<(K, V)>>`. + pub fn iter_rev<'tx, D, R, F>(&'tx self, range: R, f: F) -> D + where + D: Send + Sync, + R: 'static + RangeBounds<E::K>, + F: FnOnce( + KvIter< + BC, + CowKB<'tx, BC::KeyBytes>, + CowVB<'tx, BC::ValueBytes>, + BackendTxIter<BC>, + E::K, + E::V, + >, + ) -> D, + { + let range_bytes = crate::iter::convert_range::<E::K, R>(range); + let backend_iter = self + .col_reader + .backend_col + .iter::<E::K, E::V>(range_bytes.clone()); + f(KvIter::new( + BackendTxIter::new(backend_iter, &self.batch.tree), + range_bytes, + ) + .reverse()) + } } pub trait DbTxCollectionRw { diff --git a/rust-libs/tools/kv_typed/tests/test_db_schema.rs b/rust-libs/tools/kv_typed/tests/test_db_schema.rs index 75ef7c69868e3d7f2b729050275f0460f8f48d10..63f0cada21106fda528aafe03c56d834eb393dd6 100644 --- a/rust-libs/tools/kv_typed/tests/test_db_schema.rs +++ b/rust-libs/tools/kv_typed/tests/test_db_schema.rs @@ -90,8 +90,8 @@ fn test_db<B: Backend>(db: &TestV1Db<B>) -> KvResult<()> { Ok::<(), KvError>(()) })?; - db.col1().iter(.., |it| { - let mut iter = it.values().reverse(); + db.col1().iter_rev(.., |it| { + let mut iter = it.values(); assert_eq!(iter.next_res()?, Some("tutu".to_owned())); assert_eq!(iter.next_res()?, Some("toto".to_owned())); @@ -101,8 +101,8 @@ fn test_db<B: Backend>(db: &TestV1Db<B>) -> KvResult<()> { db.col1_write().upsert(7, "titi".to_owned())?; - db.col1().iter(.., |it| { - let mut iter = it.values().reverse().step_by(2); + db.col1().iter_rev(.., |it| { + let mut iter = it.values().step_by(2); assert_eq!(iter.next_res()?, Some("titi".to_owned())); assert_eq!(iter.next_res()?, Some("toto".to_owned())); @@ -169,7 +169,7 @@ fn test_db<B: Backend>(db: &TestV1Db<B>) -> KvResult<()> { vec![4, 42] ); assert_eq!( - c3.iter(.., |it| it.reverse().keys().collect::<KvResult<Vec<_>>>())?, + c3.iter_rev(.., |it| it.keys().collect::<KvResult<Vec<_>>>())?, vec![42, 4] ); c3.upsert(8, vec![11, 12, 13]); @@ -178,8 +178,8 @@ fn test_db<B: Backend>(db: &TestV1Db<B>) -> KvResult<()> { c3.iter(.., |it| it.keys().collect::<KvResult<Vec<_>>>())?, vec![8, 42] ); - c3.iter(.., |it| { - let iter = it.reverse().keys(); + c3.iter_rev(.., |it| { + let iter = it.keys(); r2.recv().expect("disconnected"); assert_eq!(iter.collect::<KvResult<Vec<_>>>()?, vec![42, 8]);