From cbb6efc4332490122e8de70d082c7048cc97e0a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Blankfors?= Date: Fri, 1 Nov 2024 09:02:39 +0100 Subject: [PATCH] feat: Don't require `Send` in BoxedIter --- crates/fuel-core/src/database/block.rs | 4 +- crates/fuel-core/src/graphql_api/database.rs | 13 +-- crates/fuel-core/src/graphql_api/ports.rs | 20 ++-- crates/fuel-core/src/query/message.rs | 8 +- .../service/adapters/graphql_api/off_chain.rs | 18 ++-- .../service/adapters/graphql_api/on_chain.rs | 23 +++-- .../service/genesis/importer/import_task.rs | 6 +- crates/fuel-core/src/state/data_source.rs | 5 +- .../fuel-core/src/state/generic_database.rs | 7 +- .../fuel-core/src/state/historical_rocksdb.rs | 5 +- .../src/state/in_memory/memory_store.rs | 12 +-- .../src/state/in_memory/memory_view.rs | 12 +-- .../src/state/iterable_key_value_view.rs | 5 +- crates/fuel-core/src/state/rocks_db.rs | 25 ++--- crates/storage/src/blueprint.rs | 3 +- crates/storage/src/iter.rs | 96 ++++++++++++------- crates/storage/src/iter/changes_iterator.rs | 16 ++-- crates/storage/src/kv_store.rs | 8 +- crates/storage/src/lib.rs | 2 +- crates/storage/src/structured_storage.rs | 7 +- crates/storage/src/transactional.rs | 5 +- 21 files changed, 177 insertions(+), 123 deletions(-) diff --git a/crates/fuel-core/src/database/block.rs b/crates/fuel-core/src/database/block.rs index 7c9ab130072..00b39ab23b5 100644 --- a/crates/fuel-core/src/database/block.rs +++ b/crates/fuel-core/src/database/block.rs @@ -7,7 +7,7 @@ use crate::{ }; use fuel_core_storage::{ iter::{ - IntoBoxedIter, + IntoBoxedIterSend, IterDirection, IteratorOverTable, }, @@ -68,7 +68,7 @@ impl OnChainIterableKeyValueView { let db_block = self.storage::().get(height)?; if let Some(block) = db_block { - let transaction_ids = block.transactions().iter().into_boxed(); + let transaction_ids = block.transactions().iter().into_boxed_send(); let txs = >::get_batch( self, transaction_ids, diff --git a/crates/fuel-core/src/graphql_api/database.rs b/crates/fuel-core/src/graphql_api/database.rs index bb1d54049a1..287189c9025 100644 --- a/crates/fuel-core/src/graphql_api/database.rs +++ b/crates/fuel-core/src/graphql_api/database.rs @@ -8,7 +8,8 @@ use crate::fuel_core_graphql_api::{ use fuel_core_services::yield_stream::StreamYieldExt; use fuel_core_storage::{ iter::{ - BoxedIter, + BoxedIterSend, + IntoBoxedIterSend, IntoBoxedIter, IterDirection, }, @@ -205,7 +206,7 @@ impl ReadView { &self, height: Option, direction: IterDirection, - ) -> BoxedIter<'_, StorageResult> { + ) -> BoxedIterSend<'_, StorageResult> { // Chain together blocks from the off-chain db and the on-chain db // The blocks in off-chain db, if any, are from time before regenesis @@ -218,12 +219,12 @@ impl ReadView { .on_chain .blocks(Some(height), direction) .chain(self.off_chain.old_blocks(None, direction)) - .into_boxed(), + .into_boxed_send(), (false, IterDirection::Forward) => self .off_chain .old_blocks(Some(height), direction) .chain(self.on_chain.blocks(None, direction)) - .into_boxed(), + .into_boxed_send(), (false, IterDirection::Reverse) => { self.off_chain.old_blocks(Some(height), direction) } @@ -234,12 +235,12 @@ impl ReadView { .off_chain .old_blocks(None, direction) .chain(self.on_chain.blocks(None, direction)) - .into_boxed(), + .into_boxed_send(), IterDirection::Reverse => self .on_chain .blocks(None, direction) .chain(self.off_chain.old_blocks(None, direction)) - .into_boxed(), + .into_boxed_send(), } } } diff --git a/crates/fuel-core/src/graphql_api/ports.rs b/crates/fuel-core/src/graphql_api/ports.rs index 1e65554853d..243b0894bcc 100644 --- a/crates/fuel-core/src/graphql_api/ports.rs +++ b/crates/fuel-core/src/graphql_api/ports.rs @@ -2,6 +2,7 @@ use async_trait::async_trait; use fuel_core_services::stream::BoxStream; use fuel_core_storage::{ iter::{ + BoxedIterSend, BoxedIter, IterDirection, }, @@ -79,21 +80,21 @@ pub trait OffChainDatabase: Send + Sync { owner: &Address, start_coin: Option, direction: IterDirection, - ) -> BoxedIter<'_, StorageResult>; + ) -> BoxedIterSend<'_, StorageResult>; fn owned_message_ids( &self, owner: &Address, start_message_id: Option, direction: IterDirection, - ) -> BoxedIter<'_, StorageResult>; + ) -> BoxedIterSend<'_, StorageResult>; fn owned_transactions_ids( &self, owner: Address, start: Option, direction: IterDirection, - ) -> BoxedIter>; + ) -> BoxedIterSend>; fn contract_salt(&self, contract_id: &ContractId) -> StorageResult; @@ -103,7 +104,7 @@ pub trait OffChainDatabase: Send + Sync { &self, height: Option, direction: IterDirection, - ) -> BoxedIter<'_, StorageResult>; + ) -> BoxedIterSend<'_, StorageResult>; fn old_block_consensus(&self, height: &BlockHeight) -> StorageResult; @@ -156,7 +157,7 @@ pub trait DatabaseBlocks { &self, height: Option, direction: IterDirection, - ) -> BoxedIter<'_, StorageResult>; + ) -> BoxedIterSend<'_, StorageResult>; fn latest_height(&self) -> StorageResult; @@ -178,7 +179,7 @@ pub trait DatabaseMessages: StorageInspect { &self, start_message_id: Option, direction: IterDirection, - ) -> BoxedIter<'_, StorageResult>; + ) -> BoxedIterSend<'_, StorageResult>; fn message_batch<'a>( &'a self, @@ -199,7 +200,10 @@ pub trait DatabaseRelayedTransactions { pub trait DatabaseCoins: StorageInspect { fn coin(&self, utxo_id: UtxoId) -> StorageResult; - fn coins<'a>(&'a self, utxo_ids: &'a [UtxoId]) -> BoxedIter<'a, StorageResult>; + fn coins<'a>( + &'a self, + utxo_ids: &'a [UtxoId], + ) -> BoxedIter<'a, StorageResult>; } /// Trait that specifies all the getters required for contract. @@ -212,7 +216,7 @@ pub trait DatabaseContracts: contract: ContractId, start_asset: Option, direction: IterDirection, - ) -> BoxedIter>; + ) -> BoxedIterSend>; } /// Trait that specifies all the getters required for chain metadata. diff --git a/crates/fuel-core/src/query/message.rs b/crates/fuel-core/src/query/message.rs index 625c86e8ecb..f9a537dd0e2 100644 --- a/crates/fuel-core/src/query/message.rs +++ b/crates/fuel-core/src/query/message.rs @@ -1,7 +1,7 @@ use crate::fuel_core_graphql_api::database::ReadView; use fuel_core_storage::{ iter::{ - BoxedIter, + BoxedIterSend, IntoBoxedIter, IterDirection, }, @@ -53,20 +53,20 @@ pub trait MessageQueryData: Send + Sync { owner: &Address, start_message_id: Option, direction: IterDirection, - ) -> BoxedIter>; + ) -> BoxedIterSend>; fn owned_messages( &self, owner: &Address, start_message_id: Option, direction: IterDirection, - ) -> BoxedIter>; + ) -> BoxedIterSend>; fn all_messages( &self, start_message_id: Option, direction: IterDirection, - ) -> BoxedIter>; + ) -> BoxedIterSend>; } impl ReadView { diff --git a/crates/fuel-core/src/service/adapters/graphql_api/off_chain.rs b/crates/fuel-core/src/service/adapters/graphql_api/off_chain.rs index 1c0c79953d3..527ed925174 100644 --- a/crates/fuel-core/src/service/adapters/graphql_api/off_chain.rs +++ b/crates/fuel-core/src/service/adapters/graphql_api/off_chain.rs @@ -26,7 +26,9 @@ use fuel_core_storage::{ blueprint::BlueprintInspect, codec::Encode, iter::{ + BoxedIterSend, BoxedIter, + IntoBoxedIterSend, IntoBoxedIter, IterDirection, IteratorOverTable, @@ -97,10 +99,10 @@ impl OffChainDatabase for OffChainIterableKeyValueView { owner: &Address, start_coin: Option, direction: IterDirection, - ) -> BoxedIter<'_, StorageResult> { + ) -> BoxedIterSend<'_, StorageResult> { self.owned_coins_ids(owner, start_coin, Some(direction)) .map(|res| res.map_err(StorageError::from)) - .into_boxed() + .into_boxed_send() } fn owned_message_ids( @@ -108,10 +110,10 @@ impl OffChainDatabase for OffChainIterableKeyValueView { owner: &Address, start_message_id: Option, direction: IterDirection, - ) -> BoxedIter<'_, StorageResult> { + ) -> BoxedIterSend<'_, StorageResult> { self.owned_message_ids(owner, start_message_id, Some(direction)) .map(|result| result.map_err(StorageError::from)) - .into_boxed() + .into_boxed_send() } fn owned_transactions_ids( @@ -119,14 +121,14 @@ impl OffChainDatabase for OffChainIterableKeyValueView { owner: Address, start: Option, direction: IterDirection, - ) -> BoxedIter> { + ) -> BoxedIterSend> { let start = start.map(|tx_pointer| OwnedTransactionIndexCursor { block_height: tx_pointer.block_height(), tx_idx: tx_pointer.tx_index(), }); self.owned_transactions(owner, start, Some(direction)) .map(|result| result.map_err(StorageError::from)) - .into_boxed() + .into_boxed_send() } fn contract_salt(&self, contract_id: &ContractId) -> StorageResult { @@ -153,10 +155,10 @@ impl OffChainDatabase for OffChainIterableKeyValueView { &self, height: Option, direction: IterDirection, - ) -> BoxedIter<'_, StorageResult> { + ) -> BoxedIterSend<'_, StorageResult> { self.iter_all_by_start::(height.as_ref(), Some(direction)) .map(|r| r.map(|(_, block)| block)) - .into_boxed() + .into_boxed_send() } fn old_block_consensus(&self, height: &BlockHeight) -> StorageResult { diff --git a/crates/fuel-core/src/service/adapters/graphql_api/on_chain.rs b/crates/fuel-core/src/service/adapters/graphql_api/on_chain.rs index b392482237c..55d3d34712d 100644 --- a/crates/fuel-core/src/service/adapters/graphql_api/on_chain.rs +++ b/crates/fuel-core/src/service/adapters/graphql_api/on_chain.rs @@ -18,7 +18,9 @@ use crate::{ }; use fuel_core_storage::{ iter::{ + BoxedIterSend, BoxedIter, + IntoBoxedIterSend, IntoBoxedIter, IterDirection, IteratorOverTable, @@ -93,10 +95,10 @@ impl DatabaseBlocks for OnChainIterableKeyValueView { &self, height: Option, direction: IterDirection, - ) -> BoxedIter<'_, StorageResult> { + ) -> BoxedIterSend<'_, StorageResult> { self.iter_all_by_start::(height.as_ref(), Some(direction)) .map(|result| result.map(|(_, block)| block)) - .into_boxed() + .into_boxed_send() } fn latest_height(&self) -> StorageResult { @@ -116,10 +118,10 @@ impl DatabaseMessages for OnChainIterableKeyValueView { &self, start_message_id: Option, direction: IterDirection, - ) -> BoxedIter<'_, StorageResult> { + ) -> BoxedIterSend<'_, StorageResult> { self.all_messages(start_message_id, Some(direction)) .map(|result| result.map_err(StorageError::from)) - .into_boxed() + .into_boxed_send() } fn message_batch<'a>( @@ -147,12 +149,15 @@ impl DatabaseCoins for OnChainIterableKeyValueView { Ok(coin.uncompress(utxo_id)) } - fn coins<'a>(&'a self, utxo_ids: &'a [UtxoId]) -> BoxedIter<'a, StorageResult> { + fn coins<'a>( + &'a self, + utxo_ids: &'a [UtxoId], + ) -> BoxedIter<'a, StorageResult> { >::get_batch( self, - utxo_ids.iter().into_boxed(), + utxo_ids.iter().into_boxed_send(), ) - .zip(utxo_ids.iter().into_boxed()) + .zip(utxo_ids.iter().into_boxed_send()) .map(|(res, utxo_id)| { res.and_then(|opt| opt.ok_or(not_found!(Coins))) .map(|coin| coin.uncompress(*utxo_id)) @@ -167,7 +172,7 @@ impl DatabaseContracts for OnChainIterableKeyValueView { contract: ContractId, start_asset: Option, direction: IterDirection, - ) -> BoxedIter> { + ) -> BoxedIterSend> { self.filter_contract_balances(contract, start_asset, Some(direction)) .map_ok(|entry| ContractBalance { owner: *entry.key.contract_id(), @@ -175,7 +180,7 @@ impl DatabaseContracts for OnChainIterableKeyValueView { asset_id: *entry.key.asset_id(), }) .map(|res| res.map_err(StorageError::from)) - .into_boxed() + .into_boxed_send() } } diff --git a/crates/fuel-core/src/service/genesis/importer/import_task.rs b/crates/fuel-core/src/service/genesis/importer/import_task.rs index 5cdcf636c8c..5a6476f2730 100644 --- a/crates/fuel-core/src/service/genesis/importer/import_task.rs +++ b/crates/fuel-core/src/service/genesis/importer/import_task.rs @@ -166,7 +166,7 @@ mod tests { use fuel_core_storage::{ column::Column, iter::{ - BoxedIter, + BoxedIterSend, IterDirection, IterableStore, }, @@ -551,7 +551,7 @@ mod tests { _: Option<&[u8]>, _: Option<&[u8]>, _: IterDirection, - ) -> BoxedIter { + ) -> BoxedIterSend { unimplemented!() } @@ -561,7 +561,7 @@ mod tests { _: Option<&[u8]>, _: Option<&[u8]>, _: IterDirection, - ) -> BoxedIter { + ) -> BoxedIterSend { unimplemented!() } } diff --git a/crates/fuel-core/src/state/data_source.rs b/crates/fuel-core/src/state/data_source.rs index 702085aa5c2..2b13c754bce 100644 --- a/crates/fuel-core/src/state/data_source.rs +++ b/crates/fuel-core/src/state/data_source.rs @@ -4,6 +4,7 @@ use crate::{ }; use fuel_core_storage::{ iter::{ + BoxedIterSend, BoxedIter, IterDirection, IterableStore, @@ -96,7 +97,7 @@ where prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, - ) -> BoxedIter { + ) -> BoxedIterSend { self.data.iter_store(column, prefix, start, direction) } @@ -106,7 +107,7 @@ where prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, - ) -> BoxedIter { + ) -> BoxedIterSend { self.data.iter_store_keys(column, prefix, start, direction) } } diff --git a/crates/fuel-core/src/state/generic_database.rs b/crates/fuel-core/src/state/generic_database.rs index 6d0114c4508..c6b1d677dde 100644 --- a/crates/fuel-core/src/state/generic_database.rs +++ b/crates/fuel-core/src/state/generic_database.rs @@ -1,5 +1,6 @@ use fuel_core_storage::{ iter::{ + BoxedIterSend, BoxedIter, IterDirection, IterableStore, @@ -75,7 +76,7 @@ where keys: Iter, ) -> impl Iterator>> + 'a where - Iter: 'a + Iterator + Send, + Iter: 'a + IntoIterator, M::Key: 'a, { self.storage.get_batch(keys) @@ -166,7 +167,7 @@ where prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, - ) -> BoxedIter { + ) -> BoxedIterSend { self.storage.iter_store(column, prefix, start, direction) } @@ -176,7 +177,7 @@ where prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, - ) -> BoxedIter { + ) -> BoxedIterSend { self.storage .iter_store_keys(column, prefix, start, direction) } diff --git a/crates/fuel-core/src/state/historical_rocksdb.rs b/crates/fuel-core/src/state/historical_rocksdb.rs index 559505ba67b..2749673bd2b 100644 --- a/crates/fuel-core/src/state/historical_rocksdb.rs +++ b/crates/fuel-core/src/state/historical_rocksdb.rs @@ -29,6 +29,7 @@ use crate::{ use fuel_core_storage::{ iter::{ BoxedIter, + BoxedIterSend, IntoBoxedIter, IterDirection, IterableStore, @@ -433,7 +434,7 @@ where prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, - ) -> BoxedIter { + ) -> BoxedIterSend { self.db .iter_store(Column::OriginalColumn(column), prefix, start, direction) } @@ -444,7 +445,7 @@ where prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, - ) -> BoxedIter { + ) -> BoxedIterSend { self.db .iter_store_keys(Column::OriginalColumn(column), prefix, start, direction) } diff --git a/crates/fuel-core/src/state/in_memory/memory_store.rs b/crates/fuel-core/src/state/in_memory/memory_store.rs index c23eafe48e3..a839ab3ecff 100644 --- a/crates/fuel-core/src/state/in_memory/memory_store.rs +++ b/crates/fuel-core/src/state/in_memory/memory_store.rs @@ -16,8 +16,8 @@ use fuel_core_storage::{ iter::{ iterator, keys_iterator, - BoxedIter, - IntoBoxedIter, + BoxedIterSend, + IntoBoxedIterSend, IterableStore, }, kv_store::{ @@ -144,8 +144,8 @@ where prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, - ) -> BoxedIter { - self.iter_all(column, prefix, start, direction).into_boxed() + ) -> BoxedIterSend { + self.iter_all(column, prefix, start, direction).into_boxed_send() } fn iter_store_keys( @@ -154,9 +154,9 @@ where prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, - ) -> BoxedIter { + ) -> BoxedIterSend { self.iter_all_keys(column, prefix, start, direction) - .into_boxed() + .into_boxed_send() } } diff --git a/crates/fuel-core/src/state/in_memory/memory_view.rs b/crates/fuel-core/src/state/in_memory/memory_view.rs index 8047785033e..9f8c16c7b64 100644 --- a/crates/fuel-core/src/state/in_memory/memory_view.rs +++ b/crates/fuel-core/src/state/in_memory/memory_view.rs @@ -6,8 +6,8 @@ use fuel_core_storage::{ iter::{ iterator, keys_iterator, - BoxedIter, - IntoBoxedIter, + BoxedIterSend, + IntoBoxedIterSend, IterDirection, IterableStore, }, @@ -86,8 +86,8 @@ where prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, - ) -> BoxedIter { - self.iter_all(column, prefix, start, direction).into_boxed() + ) -> BoxedIterSend { + self.iter_all(column, prefix, start, direction).into_boxed_send() } fn iter_store_keys( @@ -96,8 +96,8 @@ where prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, - ) -> BoxedIter { + ) -> BoxedIterSend { self.iter_all_keys(column, prefix, start, direction) - .into_boxed() + .into_boxed_send() } } diff --git a/crates/fuel-core/src/state/iterable_key_value_view.rs b/crates/fuel-core/src/state/iterable_key_value_view.rs index f8a8870a11a..f6a4aa9459d 100644 --- a/crates/fuel-core/src/state/iterable_key_value_view.rs +++ b/crates/fuel-core/src/state/iterable_key_value_view.rs @@ -1,6 +1,7 @@ use fuel_core_storage::{ iter::{ BoxedIter, + BoxedIterSend, IterDirection, IterableStore, }, @@ -94,7 +95,7 @@ where prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, - ) -> BoxedIter { + ) -> BoxedIterSend { self.0.iter_store(column, prefix, start, direction) } @@ -104,7 +105,7 @@ where prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, - ) -> BoxedIter { + ) -> BoxedIterSend { self.0.iter_store_keys(column, prefix, start, direction) } } diff --git a/crates/fuel-core/src/state/rocks_db.rs b/crates/fuel-core/src/state/rocks_db.rs index ada8b458fa9..85761940d5c 100644 --- a/crates/fuel-core/src/state/rocks_db.rs +++ b/crates/fuel-core/src/state/rocks_db.rs @@ -16,7 +16,9 @@ use fuel_core_metrics::core_metrics::DatabaseMetrics; use fuel_core_storage::{ iter::{ BoxedIter, + BoxedIterSend, IntoBoxedIter, + IntoBoxedIterSend, IterableStore, }, kv_store::{ @@ -487,7 +489,7 @@ where true } }) - .into_boxed() + .into_boxed_send() } else { // No next item, so we can start backward iteration from the end. let prefix = prefix.to_vec(); @@ -499,7 +501,7 @@ where true } }) - .into_boxed() + .into_boxed_send() } } @@ -564,7 +566,7 @@ where prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, - ) -> BoxedIter> + ) -> BoxedIterSend> where T: ExtractItem, { @@ -578,11 +580,12 @@ where IterDirection::Reverse => IteratorMode::End, }; self.iterator::(column, self.read_options(), iter_mode) - .into_boxed() + .into_boxed_send() } (Some(prefix), None) => { if direction == IterDirection::Reverse { - self.reverse_prefix_iter::(prefix, column).into_boxed() + self.reverse_prefix_iter::(prefix, column) + .into_boxed_send() } else { // start iterating in a certain direction within the keyspace let iter_mode = IteratorMode::From( @@ -604,7 +607,7 @@ where true } }) - .into_boxed() + .into_boxed_send() } } (None, Some(start)) => { @@ -612,13 +615,13 @@ where let iter_mode = IteratorMode::From(start, convert_to_rocksdb_direction(direction)); self.iterator::(column, self.read_options(), iter_mode) - .into_boxed() + .into_boxed_send() } (Some(prefix), Some(start)) => { // TODO: Maybe we want to allow the `start` to be without a `prefix` in the future. // If the `start` doesn't have the same `prefix`, return nothing. if !start.starts_with(prefix) { - return iter::empty().into_boxed(); + return iter::empty().into_boxed_send(); } // start iterating in a certain direction from the start key @@ -634,7 +637,7 @@ where true } }) - .into_boxed() + .into_boxed_send() } } } @@ -781,7 +784,7 @@ where prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, - ) -> BoxedIter { + ) -> BoxedIterSend { self._iter_store::(column, prefix, start, direction) } @@ -791,7 +794,7 @@ where prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, - ) -> BoxedIter { + ) -> BoxedIterSend { self._iter_store::(column, prefix, start, direction) } } diff --git a/crates/storage/src/blueprint.rs b/crates/storage/src/blueprint.rs index 9845c37b967..8acdd7c79b1 100644 --- a/crates/storage/src/blueprint.rs +++ b/crates/storage/src/blueprint.rs @@ -84,10 +84,11 @@ where column: S::Column, ) -> impl Iterator>> + 'a where - Iter: 'a + Iterator + Send, + Iter: 'a + IntoIterator, M::Key: 'a, { let keys = keys + .into_iter() .map(|key| Self::KeyCodec::encode(key).into_bytes()) .into_boxed(); diff --git a/crates/storage/src/iter.rs b/crates/storage/src/iter.rs index 35c550851fb..8a3f7d33c67 100644 --- a/crates/storage/src/iter.rs +++ b/crates/storage/src/iter.rs @@ -26,10 +26,9 @@ use alloc::{ pub mod changes_iterator; -// TODO: BoxedIter to be used until RPITIT lands in stable rust. /// A boxed variant of the iterator that can be used as a return type of the traits. pub struct BoxedIter<'a, T> { - iter: Box + 'a + Send>, + iter: Box + 'a>, } impl<'a, T> Iterator for BoxedIter<'a, T> { @@ -48,7 +47,7 @@ pub trait IntoBoxedIter<'a, T> { impl<'a, T, I> IntoBoxedIter<'a, T> for I where - I: Iterator + 'a + Send, + I: Iterator + 'a, { fn into_boxed(self) -> BoxedIter<'a, T> { BoxedIter { @@ -57,6 +56,37 @@ where } } +/// A boxed iterator that can be sent to other threads. +/// This is useful for example when converting it to a `futures::Stream`. +pub struct BoxedIterSend<'a, T> { + iter: Box + 'a + Send>, +} + +impl<'a, T> Iterator for BoxedIterSend<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + self.iter.next() + } +} + +/// The traits simplifies conversion into `BoxedIter`. +pub trait IntoBoxedIterSend<'a, T> { + /// Converts `Self` iterator into `BoxedIter`. + fn into_boxed_send(self) -> BoxedIterSend<'a, T>; +} + +impl<'a, T, I> IntoBoxedIterSend<'a, T> for I +where + I: Iterator + 'a + Send, +{ + fn into_boxed_send(self) -> BoxedIterSend<'a, T> { + BoxedIterSend { + iter: Box::new(self), + } + } +} + /// A enum for iterating across the database #[derive(Copy, Clone, Debug, PartialOrd, Eq, PartialEq)] pub enum IterDirection { @@ -82,7 +112,7 @@ pub trait IterableStore: KeyValueInspect { prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, - ) -> BoxedIter; + ) -> BoxedIterSend; /// Returns an iterator over keys in the storage. fn iter_store_keys( @@ -91,7 +121,7 @@ pub trait IterableStore: KeyValueInspect { prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, - ) -> BoxedIter; + ) -> BoxedIterSend; } #[cfg(feature = "std")] @@ -105,7 +135,7 @@ where prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, - ) -> BoxedIter { + ) -> BoxedIterSend { use core::ops::Deref; self.deref().iter_store(column, prefix, start, direction) } @@ -116,7 +146,7 @@ where prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, - ) -> BoxedIter { + ) -> BoxedIterSend { use core::ops::Deref; self.deref() .iter_store_keys(column, prefix, start, direction) @@ -134,7 +164,7 @@ where prefix: Option

, start: Option<&M::Key>, direction: Option, - ) -> BoxedIter> + ) -> BoxedIterSend> where P: AsRef<[u8]>; @@ -144,7 +174,7 @@ where prefix: Option

, start: Option<&M::Key>, direction: Option, - ) -> BoxedIter> + ) -> BoxedIterSend> where P: AsRef<[u8]>; } @@ -160,7 +190,7 @@ where prefix: Option

, start: Option<&M::Key>, direction: Option, - ) -> BoxedIter> + ) -> BoxedIterSend> where P: AsRef<[u8]>, { @@ -186,7 +216,7 @@ where Ok(key) }) }) - .into_boxed() + .into_boxed_send() } fn iter_table

( @@ -194,7 +224,7 @@ where prefix: Option

, start: Option<&M::Key>, direction: Option, - ) -> BoxedIter> + ) -> BoxedIterSend> where P: AsRef<[u8]>, { @@ -225,7 +255,7 @@ where Ok((key, value)) }) }) - .into_boxed() + .into_boxed_send() } } @@ -235,7 +265,7 @@ pub trait IteratorOverTable { fn iter_all_keys( &self, direction: Option, - ) -> BoxedIter> + ) -> BoxedIterSend> where M: Mappable, Self: IterableTable, @@ -247,7 +277,7 @@ pub trait IteratorOverTable { fn iter_all_by_prefix_keys( &self, prefix: Option

, - ) -> BoxedIter> + ) -> BoxedIterSend> where M: Mappable, P: AsRef<[u8]>, @@ -261,7 +291,7 @@ pub trait IteratorOverTable { &self, start: Option<&M::Key>, direction: Option, - ) -> BoxedIter> + ) -> BoxedIterSend> where M: Mappable, Self: IterableTable, @@ -275,7 +305,7 @@ pub trait IteratorOverTable { prefix: Option

, start: Option<&M::Key>, direction: Option, - ) -> BoxedIter> + ) -> BoxedIterSend> where M: Mappable, P: AsRef<[u8]>, @@ -288,7 +318,7 @@ pub trait IteratorOverTable { fn iter_all( &self, direction: Option, - ) -> BoxedIter> + ) -> BoxedIterSend> where M: Mappable, Self: IterableTable, @@ -300,7 +330,7 @@ pub trait IteratorOverTable { fn iter_all_by_prefix( &self, prefix: Option

, - ) -> BoxedIter> + ) -> BoxedIterSend> where M: Mappable, P: AsRef<[u8]>, @@ -314,7 +344,7 @@ pub trait IteratorOverTable { &self, start: Option<&M::Key>, direction: Option, - ) -> BoxedIter> + ) -> BoxedIterSend> where M: Mappable, Self: IterableTable, @@ -328,7 +358,7 @@ pub trait IteratorOverTable { prefix: Option

, start: Option<&M::Key>, direction: Option, - ) -> BoxedIter> + ) -> BoxedIterSend> where M: Mappable, P: AsRef<[u8]>, @@ -353,9 +383,9 @@ where match (prefix, start) { (None, None) => { if direction == IterDirection::Forward { - tree.iter().into_boxed() + tree.iter().into_boxed_send() } else { - tree.iter().rev().into_boxed() + tree.iter().rev().into_boxed_send() } } (Some(prefix), None) => { @@ -363,23 +393,23 @@ where if direction == IterDirection::Forward { tree.range(prefix.clone()..) .take_while(move |(key, _)| key.starts_with(prefix.as_slice())) - .into_boxed() + .into_boxed_send() } else { let mut vec: Vec<_> = tree .range(prefix.clone()..) - .into_boxed() + .into_boxed_send() .take_while(|(key, _)| key.starts_with(prefix.as_slice())) .collect(); vec.reverse(); - vec.into_iter().into_boxed() + vec.into_iter().into_boxed_send() } } (None, Some(start)) => { if direction == IterDirection::Forward { - tree.range(start.to_vec()..).into_boxed() + tree.range(start.to_vec()..).into_boxed_send() } else { - tree.range(..=start.to_vec()).rev().into_boxed() + tree.range(..=start.to_vec()).rev().into_boxed_send() } } (Some(prefix), Some(start)) => { @@ -387,12 +417,12 @@ where if direction == IterDirection::Forward { tree.range(start.to_vec()..) .take_while(move |(key, _)| key.starts_with(prefix.as_slice())) - .into_boxed() + .into_boxed_send() } else { tree.range(..=start.to_vec()) .rev() .take_while(move |(key, _)| key.starts_with(prefix.as_slice())) - .into_boxed() + .into_boxed_send() } } } @@ -411,14 +441,14 @@ where match (prefix, start) { (None, None) => { if direction == IterDirection::Forward { - tree.keys().into_boxed() + tree.keys().into_boxed_send() } else { - tree.keys().rev().into_boxed() + tree.keys().rev().into_boxed_send() } } // all the other cases require using a range, so we can't use the keys() method (_, _) => iterator(tree, prefix, start, direction) .map(|(key, _)| key) - .into_boxed(), + .into_boxed_send(), } } diff --git a/crates/storage/src/iter/changes_iterator.rs b/crates/storage/src/iter/changes_iterator.rs index 9a3e566bdf3..b5260392c4f 100644 --- a/crates/storage/src/iter/changes_iterator.rs +++ b/crates/storage/src/iter/changes_iterator.rs @@ -2,8 +2,8 @@ use crate::{ iter::{ - BoxedIter, - IntoBoxedIter, + BoxedIterSend, + IntoBoxedIterSend, IterDirection, IterableStore, }, @@ -61,7 +61,7 @@ where prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, - ) -> BoxedIter { + ) -> BoxedIterSend { if let Some(tree) = self.changes.get(&column.id()) { crate::iter::iterator(tree, prefix, start, direction) .filter_map(|(key, value)| match value { @@ -71,9 +71,9 @@ where WriteOperation::Remove => None, }) .map(Ok) - .into_boxed() + .into_boxed_send() } else { - core::iter::empty().into_boxed() + core::iter::empty().into_boxed_send() } } @@ -83,7 +83,7 @@ where prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, - ) -> BoxedIter { + ) -> BoxedIterSend { // We cannot define iter_store_keys appropriately for the `ChangesIterator`, // because we have to filter out the keys that were removed, which are // marked as `WriteOperation::Remove` in the value @@ -95,9 +95,9 @@ where WriteOperation::Remove => None, }) .map(Ok) - .into_boxed() + .into_boxed_send() } else { - core::iter::empty().into_boxed() + core::iter::empty().into_boxed_send() } } } diff --git a/crates/storage/src/kv_store.rs b/crates/storage/src/kv_store.rs index 7d4564395d3..9eb3b25bf34 100644 --- a/crates/storage/src/kv_store.rs +++ b/crates/storage/src/kv_store.rs @@ -1,7 +1,10 @@ //! The module provides plain abstract definition of the key-value store. use crate::{ - iter::BoxedIter, + iter::{ + BoxedIter, + IntoBoxedIter, + }, Error as StorageError, Result as StorageResult, }; @@ -14,7 +17,6 @@ use alloc::{ vec::Vec, }; -use crate::iter::IntoBoxedIter; #[cfg(feature = "std")] use core::ops::Deref; @@ -44,7 +46,7 @@ pub trait StorageColumn: Copy + core::fmt::Debug + Send + Sync + 'static { /// The definition of the key-value inspection store. #[impl_tools::autoimpl(for &T, &mut T, Box)] -pub trait KeyValueInspect: Send + Sync { +pub trait KeyValueInspect { /// The type of the column. type Column: StorageColumn; diff --git a/crates/storage/src/lib.rs b/crates/storage/src/lib.rs index 1977dacd1ef..6ce8c2fd8cf 100644 --- a/crates/storage/src/lib.rs +++ b/crates/storage/src/lib.rs @@ -186,7 +186,7 @@ pub trait StorageBatchInspect { keys: Iter, ) -> impl Iterator>> + 'a where - Iter: 'a + Iterator + Send, + Iter: 'a + IntoIterator, Type::Key: 'a; } diff --git a/crates/storage/src/structured_storage.rs b/crates/storage/src/structured_storage.rs index 3bdb6f2f30b..882308bc8ad 100644 --- a/crates/storage/src/structured_storage.rs +++ b/crates/storage/src/structured_storage.rs @@ -15,6 +15,7 @@ use crate::{ }, iter::{ BoxedIter, + BoxedIterSend, IterDirection, IterableStore, }, @@ -240,7 +241,7 @@ where prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, - ) -> BoxedIter { + ) -> BoxedIterSend { self.inner.iter_store(column, prefix, start, direction) } @@ -250,7 +251,7 @@ where prefix: Option<&[u8]>, start: Option<&[u8]>, direction: IterDirection, - ) -> BoxedIter { + ) -> BoxedIterSend { self.inner.iter_store_keys(column, prefix, start, direction) } } @@ -294,7 +295,7 @@ where keys: Iter, ) -> impl Iterator>> + 'a where - Iter: 'a + Iterator + Send, + Iter: 'a + IntoIterator, M::Key: 'a, { M::Blueprint::get_batch(self, keys, M::column()) diff --git a/crates/storage/src/transactional.rs b/crates/storage/src/transactional.rs index 9041b56e07e..804f495d415 100644 --- a/crates/storage/src/transactional.rs +++ b/crates/storage/src/transactional.rs @@ -32,6 +32,7 @@ use alloc::{ #[cfg(feature = "test-helpers")] use crate::{ iter::{ + BoxedIterSend, IterDirection, IterableStore, }, @@ -550,7 +551,7 @@ where _: Option<&[u8]>, _: Option<&[u8]>, _: IterDirection, - ) -> BoxedIter { + ) -> BoxedIterSend { unimplemented!() } @@ -560,7 +561,7 @@ where _: Option<&[u8]>, _: Option<&[u8]>, _: IterDirection, - ) -> BoxedIter { + ) -> BoxedIterSend { unimplemented!() } }