diff --git a/Cargo.lock b/Cargo.lock index c755be63042b..40aaf2d0d9e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3332,7 +3332,6 @@ dependencies = [ "cumulus-primitives-parachain-inherent", "cumulus-relay-chain-interface", "futures", - "lru 0.10.1", "parity-scale-codec", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -3344,6 +3343,7 @@ dependencies = [ "sc-consensus-babe", "sc-consensus-slots", "sc-telemetry", + "schnellru", "sp-api", "sp-application-crypto", "sp-block-builder", @@ -3822,7 +3822,6 @@ dependencies = [ "cumulus-relay-chain-interface", "cumulus-relay-chain-rpc-interface", "futures", - "lru 0.11.0", "polkadot-availability-recovery", "polkadot-collator-protocol", "polkadot-core-primitives", @@ -3839,6 +3838,7 @@ dependencies = [ "sc-service", "sc-tracing", "sc-utils", + "schnellru", "sp-api", "sp-consensus", "sp-consensus-babe", @@ -3857,7 +3857,6 @@ dependencies = [ "futures", "futures-timer", "jsonrpsee", - "lru 0.11.0", "parity-scale-codec", "pin-project", "polkadot-overseer", @@ -3865,6 +3864,7 @@ dependencies = [ "sc-client-api", "sc-rpc-api", "sc-service", + "schnellru", "serde", "serde_json", "smoldot", @@ -7765,9 +7765,6 @@ name = "lru" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eedb2bdbad7e0634f83989bf596f497b070130daaa398ab22d84c39e266deec5" -dependencies = [ - "hashbrown 0.14.0", -] [[package]] name = "lru-cache" @@ -11696,7 +11693,6 @@ dependencies = [ "fatality", "futures", "futures-timer", - "lru 0.11.0", "parity-scale-codec", "polkadot-erasure-coding", "polkadot-node-network-protocol", @@ -11708,6 +11704,7 @@ dependencies = [ "polkadot-primitives-test-helpers", "rand 0.8.5", "sc-network", + "schnellru", "sp-core", "sp-keyring", "sp-keystore", @@ -11726,7 +11723,6 @@ dependencies = [ "futures", "futures-timer", "log", - "lru 0.11.0", "parity-scale-codec", "polkadot-erasure-coding", "polkadot-node-network-protocol", @@ -11738,6 +11734,7 @@ dependencies = [ "polkadot-primitives-test-helpers", "rand 0.8.5", "sc-network", + "schnellru", "sp-application-crypto", "sp-core", "sp-keyring", @@ -11827,7 +11824,6 @@ dependencies = [ "futures-timer", "indexmap 1.9.3", "lazy_static", - "lru 0.11.0", "parity-scale-codec", "polkadot-erasure-coding", "polkadot-node-network-protocol", @@ -11839,6 +11835,7 @@ dependencies = [ "polkadot-primitives-test-helpers", "sc-keystore", "sc-network", + "schnellru", "sp-application-crypto", "sp-keyring", "sp-keystore", @@ -11951,7 +11948,6 @@ dependencies = [ "futures-timer", "kvdb", "kvdb-memorydb", - "lru 0.11.0", "merlin 2.0.1", "parity-scale-codec", "parking_lot 0.12.1", @@ -11965,6 +11961,7 @@ dependencies = [ "polkadot-primitives-test-helpers", "rand_core 0.5.1", "sc-keystore", + "schnellru", "schnorrkel 0.9.1", "sp-application-crypto", "sp-consensus", @@ -12125,7 +12122,6 @@ dependencies = [ "futures-timer", "kvdb", "kvdb-memorydb", - "lru 0.11.0", "parity-scale-codec", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -12134,6 +12130,7 @@ dependencies = [ "polkadot-primitives", "polkadot-primitives-test-helpers", "sc-keystore", + "schnellru", "sp-application-crypto", "sp-core", "sp-keyring", @@ -12333,7 +12330,6 @@ version = "1.0.0" dependencies = [ "async-trait", "futures", - "lru 0.11.0", "polkadot-node-metrics", "polkadot-node-primitives", "polkadot-node-subsystem", @@ -12341,6 +12337,7 @@ dependencies = [ "polkadot-node-subsystem-types", "polkadot-primitives", "polkadot-primitives-test-helpers", + "schnellru", "sp-api", "sp-consensus-babe", "sp-core", @@ -12504,7 +12501,6 @@ dependencies = [ "kvdb-shared-tests", "lazy_static", "log", - "lru 0.11.0", "parity-db", "parity-scale-codec", "parking_lot 0.11.2", @@ -12520,6 +12516,7 @@ dependencies = [ "polkadot-primitives-test-helpers", "prioritized-metered-channel", "rand 0.8.5", + "schnellru", "sp-application-crypto", "sp-core", "sp-keystore", @@ -12537,7 +12534,6 @@ dependencies = [ "femme", "futures", "futures-timer", - "lru 0.11.0", "orchestra", "parking_lot 0.12.1", "polkadot-node-metrics", @@ -12548,6 +12544,7 @@ dependencies = [ "polkadot-primitives-test-helpers", "prioritized-metered-channel", "sc-client-api", + "schnellru", "sp-api", "sp-core", "tikv-jemalloc-ctl", @@ -12992,7 +12989,6 @@ dependencies = [ "kvdb", "kvdb-rocksdb", "log", - "lru 0.11.0", "mmr-gadget", "pallet-babe", "pallet-im-online", @@ -13066,6 +13062,7 @@ dependencies = [ "sc-telemetry", "sc-transaction-pool", "sc-transaction-pool-api", + "schnellru", "serde", "serde_json", "serial_test", diff --git a/cumulus/client/consensus/aura/Cargo.toml b/cumulus/client/consensus/aura/Cargo.toml index d5781d5ed812..030ab705f160 100644 --- a/cumulus/client/consensus/aura/Cargo.toml +++ b/cumulus/client/consensus/aura/Cargo.toml @@ -10,7 +10,7 @@ async-trait = "0.1.73" codec = { package = "parity-scale-codec", version = "3.0.0", features = [ "derive" ] } futures = "0.3.28" tracing = "0.1.37" -lru = "0.10.0" +schnellru = "0.2.1" # Substrate sc-client-api = { path = "../../../../substrate/client/api" } diff --git a/cumulus/client/consensus/aura/src/equivocation_import_queue.rs b/cumulus/client/consensus/aura/src/equivocation_import_queue.rs index 682b7b91a655..919e0da39b1a 100644 --- a/cumulus/client/consensus/aura/src/equivocation_import_queue.rs +++ b/cumulus/client/consensus/aura/src/equivocation_import_queue.rs @@ -21,7 +21,7 @@ /// should be thrown out and which ones should be kept. use codec::Codec; use cumulus_client_consensus_common::ParachainBlockImportMarker; -use lru::LruCache; +use schnellru::{ByLength, LruMap}; use sc_consensus::{ import_queue::{BasicQueue, Verifier as VerifierT}, @@ -36,27 +36,28 @@ use sp_consensus_aura::{AuraApi, Slot, SlotDuration}; use sp_core::crypto::Pair; use sp_inherents::{CreateInherentDataProviders, InherentDataProvider}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; -use std::{fmt::Debug, num::NonZeroUsize, sync::Arc}; +use std::{fmt::Debug, sync::Arc}; -const LRU_WINDOW: usize = 256; +const LRU_WINDOW: u32 = 256; const EQUIVOCATION_LIMIT: usize = 16; struct NaiveEquivocationDefender { - cache: LruCache, + cache: LruMap, } impl Default for NaiveEquivocationDefender { fn default() -> Self { - NaiveEquivocationDefender { - cache: LruCache::new(NonZeroUsize::new(LRU_WINDOW).expect("window > 0; qed")), - } + NaiveEquivocationDefender { cache: LruMap::new(ByLength::new(LRU_WINDOW)) } } } impl NaiveEquivocationDefender { // return `true` if equivocation is beyond the limit. fn insert_and_check(&mut self, slot: Slot) -> bool { - let val = self.cache.get_or_insert_mut(*slot, || 0); + let val = self + .cache + .get_or_insert(*slot, || 0) + .expect("insertion with ByLength limiter always succeeds; qed"); if *val == EQUIVOCATION_LIMIT { true } else { diff --git a/cumulus/client/relay-chain-minimal-node/Cargo.toml b/cumulus/client/relay-chain-minimal-node/Cargo.toml index 7fc53d17470a..c3914573aabf 100644 --- a/cumulus/client/relay-chain-minimal-node/Cargo.toml +++ b/cumulus/client/relay-chain-minimal-node/Cargo.toml @@ -36,7 +36,7 @@ cumulus-relay-chain-rpc-interface = { path = "../relay-chain-rpc-interface" } cumulus-primitives-core = { path = "../../primitives/core" } array-bytes = "6.1" -lru = "0.11.0" +schnellru = "0.2.1" tracing = "0.1.37" async-trait = "0.1.73" futures = "0.3.28" diff --git a/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs b/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs index 4d843eb224f2..0acd04e73cd8 100644 --- a/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs +++ b/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs @@ -15,7 +15,7 @@ // along with Polkadot. If not, see . use futures::{select, StreamExt}; -use lru::LruCache; +use schnellru::{ByLength, LruMap}; use std::sync::Arc; use polkadot_availability_recovery::AvailabilityRecoverySubsystem; @@ -157,7 +157,7 @@ fn build_overseer( .span_per_active_leaf(Default::default()) .active_leaves(Default::default()) .supports_parachains(runtime_client) - .known_leaves(LruCache::new(KNOWN_LEAVES_CACHE_SIZE)) + .known_leaves(LruMap::new(ByLength::new(KNOWN_LEAVES_CACHE_SIZE))) .metrics(Metrics::register(registry)?) .spawner(spawner); diff --git a/cumulus/client/relay-chain-rpc-interface/Cargo.toml b/cumulus/client/relay-chain-rpc-interface/Cargo.toml index d73b9ae8989a..2356e7473336 100644 --- a/cumulus/client/relay-chain-rpc-interface/Cargo.toml +++ b/cumulus/client/relay-chain-rpc-interface/Cargo.toml @@ -34,7 +34,7 @@ async-trait = "0.1.73" url = "2.4.0" serde_json = "1.0.105" serde = "1.0.183" -lru = "0.11.0" +schnellru = "0.2.1" smoldot = { version = "0.11.0", default_features = false, features = ["std"]} smoldot-light = { version = "0.9.0", default_features = false, features = ["std"] } either = "1.8.1" diff --git a/cumulus/client/relay-chain-rpc-interface/src/reconnecting_ws_client.rs b/cumulus/client/relay-chain-rpc-interface/src/reconnecting_ws_client.rs index 5add8a96ef10..5a35b2b5bfa0 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/reconnecting_ws_client.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/reconnecting_ws_client.rs @@ -31,10 +31,10 @@ use jsonrpsee::{ }, ws_client::WsClientBuilder, }; -use lru::LruCache; use sc_rpc_api::chain::ChainApiClient; +use schnellru::{ByLength, LruMap}; use sp_runtime::generic::SignedBlock; -use std::{num::NonZeroUsize, sync::Arc}; +use std::sync::Arc; use tokio::sync::mpsc::{ channel as tokio_channel, Receiver as TokioReceiver, Sender as TokioSender, }; @@ -307,8 +307,7 @@ impl ReconnectingWebsocketWorker { return }; - let mut imported_blocks_cache = - LruCache::new(NonZeroUsize::new(40).expect("40 is nonzero; qed.")); + let mut imported_blocks_cache = LruMap::new(ByLength::new(40)); let mut should_reconnect = ConnectionStatus::Connected; let mut last_seen_finalized_num: RelayNumber = 0; loop { @@ -365,7 +364,7 @@ impl ReconnectingWebsocketWorker { match import_event { Some(Ok(header)) => { let hash = header.hash(); - if imported_blocks_cache.contains(&hash) { + if imported_blocks_cache.peek(&hash).is_some() { tracing::debug!( target: LOG_TARGET, number = header.number, @@ -374,7 +373,7 @@ impl ReconnectingWebsocketWorker { ); continue; } - imported_blocks_cache.put(hash, ()); + imported_blocks_cache.insert(hash, ()); distribute_header(header, &mut self.imported_header_listeners); }, None => { diff --git a/polkadot/node/core/approval-voting/Cargo.toml b/polkadot/node/core/approval-voting/Cargo.toml index 5ae99d44d0a5..593f6bff4c83 100644 --- a/polkadot/node/core/approval-voting/Cargo.toml +++ b/polkadot/node/core/approval-voting/Cargo.toml @@ -11,7 +11,7 @@ futures-timer = "3.0.2" parity-scale-codec = { version = "3.6.1", default-features = false, features = ["bit-vec", "derive"] } gum = { package = "tracing-gum", path = "../../gum" } bitvec = { version = "1.0.0", default-features = false, features = ["alloc"] } -lru = "0.11.0" +schnellru = "0.2.1" merlin = "2.0" schnorrkel = "0.9.1" kvdb = "0.13.0" diff --git a/polkadot/node/core/approval-voting/src/import.rs b/polkadot/node/core/approval-voting/src/import.rs index c504ba71b3c2..6f376fc6fcc1 100644 --- a/polkadot/node/core/approval-voting/src/import.rs +++ b/polkadot/node/core/approval-voting/src/import.rs @@ -643,7 +643,7 @@ pub(crate) mod tests { blank_state(), RuntimeInfo::new_with_config(RuntimeInfoConfig { keystore: None, - session_cache_lru_size: DISPUTE_WINDOW.into(), + session_cache_lru_size: DISPUTE_WINDOW.get(), }), ) } @@ -755,7 +755,7 @@ pub(crate) mod tests { let mut runtime_info = RuntimeInfo::new_with_config(RuntimeInfoConfig { keystore: None, - session_cache_lru_size: DISPUTE_WINDOW.into(), + session_cache_lru_size: DISPUTE_WINDOW.get(), }); let header = header.clone(); @@ -878,7 +878,7 @@ pub(crate) mod tests { let test_fut = { let mut runtime_info = RuntimeInfo::new_with_config(RuntimeInfoConfig { keystore: None, - session_cache_lru_size: DISPUTE_WINDOW.into(), + session_cache_lru_size: DISPUTE_WINDOW.get(), }); let header = header.clone(); @@ -994,7 +994,7 @@ pub(crate) mod tests { let test_fut = { let mut runtime_info = RuntimeInfo::new_with_config(RuntimeInfoConfig { keystore: None, - session_cache_lru_size: DISPUTE_WINDOW.into(), + session_cache_lru_size: DISPUTE_WINDOW.get(), }); let header = header.clone(); @@ -1092,7 +1092,7 @@ pub(crate) mod tests { let mut runtime_info = RuntimeInfo::new_with_config(RuntimeInfoConfig { keystore: None, - session_cache_lru_size: DISPUTE_WINDOW.into(), + session_cache_lru_size: DISPUTE_WINDOW.get(), }); let header = header.clone(); diff --git a/polkadot/node/core/approval-voting/src/lib.rs b/polkadot/node/core/approval-voting/src/lib.rs index b29e47b4c435..e99572b31c4b 100644 --- a/polkadot/node/core/approval-voting/src/lib.rs +++ b/polkadot/node/core/approval-voting/src/lib.rs @@ -69,11 +69,12 @@ use std::{ collections::{ btree_map::Entry as BTMEntry, hash_map::Entry as HMEntry, BTreeMap, HashMap, HashSet, }, - num::NonZeroUsize, sync::Arc, time::Duration, }; +use schnellru::{ByLength, LruMap}; + use approval_checking::RequiredTranches; use criteria::{AssignmentCriteria, RealAssignmentCriteria}; use persisted_entries::{ApprovalEntry, BlockEntry, CandidateEntry}; @@ -102,10 +103,7 @@ const APPROVAL_CHECKING_TIMEOUT: Duration = Duration::from_secs(120); /// Value rather arbitrarily: Should not be hit in practice, it exists to more easily diagnose dead /// lock issues for example. const WAIT_FOR_SIGS_TIMEOUT: Duration = Duration::from_millis(500); -const APPROVAL_CACHE_SIZE: NonZeroUsize = match NonZeroUsize::new(1024) { - Some(cap) => cap, - None => panic!("Approval cache size must be non-zero."), -}; +const APPROVAL_CACHE_SIZE: u32 = 1024; const TICK_TOO_FAR_IN_FUTURE: Tick = 20; // 10 seconds. const APPROVAL_DELAY: Tick = 2; @@ -627,7 +625,7 @@ impl CurrentlyCheckingSet { pub async fn next( &mut self, - approvals_cache: &mut lru::LruCache, + approvals_cache: &mut LruMap, ) -> (HashSet, ApprovalState) { if !self.currently_checking.is_empty() { if let Some(approval_state) = self.currently_checking.next().await { @@ -635,7 +633,8 @@ impl CurrentlyCheckingSet { .candidate_hash_map .remove(&approval_state.candidate_hash) .unwrap_or_default(); - approvals_cache.put(approval_state.candidate_hash, approval_state.approval_outcome); + approvals_cache + .insert(approval_state.candidate_hash, approval_state.approval_outcome); return (out, approval_state) } } @@ -782,11 +781,11 @@ where // `None` on start-up. Gets initialized/updated on leaf update let mut session_info_provider = RuntimeInfo::new_with_config(RuntimeInfoConfig { keystore: None, - session_cache_lru_size: DISPUTE_WINDOW.into(), + session_cache_lru_size: DISPUTE_WINDOW.get(), }); let mut wakeups = Wakeups::default(); let mut currently_checking_set = CurrentlyCheckingSet::default(); - let mut approvals_cache = lru::LruCache::new(APPROVAL_CACHE_SIZE); + let mut approvals_cache = LruMap::new(ByLength::new(APPROVAL_CACHE_SIZE)); let mut last_finalized_height: Option = { let (tx, rx) = oneshot::channel(); @@ -922,7 +921,7 @@ async fn handle_actions( metrics: &Metrics, wakeups: &mut Wakeups, currently_checking_set: &mut CurrentlyCheckingSet, - approvals_cache: &mut lru::LruCache, + approvals_cache: &mut LruMap, mode: &mut Mode, actions: Vec, ) -> SubsystemResult { diff --git a/polkadot/node/core/dispute-coordinator/Cargo.toml b/polkadot/node/core/dispute-coordinator/Cargo.toml index 465c108211e3..5698114d278f 100644 --- a/polkadot/node/core/dispute-coordinator/Cargo.toml +++ b/polkadot/node/core/dispute-coordinator/Cargo.toml @@ -11,7 +11,7 @@ gum = { package = "tracing-gum", path = "../../gum" } parity-scale-codec = "3.6.1" kvdb = "0.13.0" thiserror = "1.0.31" -lru = "0.11.0" +schnellru = "0.2.1" fatality = "0.0.6" polkadot-primitives = { path = "../../../primitives" } diff --git a/polkadot/node/core/dispute-coordinator/src/lib.rs b/polkadot/node/core/dispute-coordinator/src/lib.rs index a2c500e08e28..f7e3d0657f2d 100644 --- a/polkadot/node/core/dispute-coordinator/src/lib.rs +++ b/polkadot/node/core/dispute-coordinator/src/lib.rs @@ -25,7 +25,7 @@ //! When importing a dispute vote from another node, this will trigger dispute participation to //! recover and validate the block. -use std::{num::NonZeroUsize, sync::Arc}; +use std::sync::Arc; use futures::FutureExt; @@ -222,8 +222,7 @@ impl DisputeCoordinatorSubsystem { // keep all sessions for a dispute window let mut runtime_info = RuntimeInfo::new_with_config(RuntimeInfoConfig { keystore: None, - session_cache_lru_size: NonZeroUsize::new(DISPUTE_WINDOW.get() as usize) - .expect("DISPUTE_WINDOW can't be 0; qed."), + session_cache_lru_size: DISPUTE_WINDOW.get(), }); let mut overlay_db = OverlayedBackend::new(&mut backend); let ( diff --git a/polkadot/node/core/dispute-coordinator/src/scraping/mod.rs b/polkadot/node/core/dispute-coordinator/src/scraping/mod.rs index f93ad0abab91..67434bca85d4 100644 --- a/polkadot/node/core/dispute-coordinator/src/scraping/mod.rs +++ b/polkadot/node/core/dispute-coordinator/src/scraping/mod.rs @@ -14,13 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use std::{ - collections::{BTreeMap, HashSet}, - num::NonZeroUsize, -}; +use std::collections::{BTreeMap, HashSet}; use futures::channel::oneshot; -use lru::LruCache; +use schnellru::{ByLength, LruMap}; use polkadot_node_primitives::{DISPUTE_CANDIDATE_LIFETIME_AFTER_FINALIZATION, MAX_FINALITY_LAG}; use polkadot_node_subsystem::{ @@ -52,10 +49,7 @@ mod candidates; /// `last_observed_blocks` LRU. This means, this value should the very least be as large as the /// number of expected forks for keeping chain scraping efficient. Making the LRU much larger than /// that has very limited use. -const LRU_OBSERVED_BLOCKS_CAPACITY: NonZeroUsize = match NonZeroUsize::new(20) { - Some(cap) => cap, - None => panic!("Observed blocks cache size must be non-zero"), -}; +const LRU_OBSERVED_BLOCKS_CAPACITY: u32 = 20; /// `ScrapedUpdates` /// @@ -173,7 +167,7 @@ pub struct ChainScraper { /// /// We assume that ancestors of cached blocks are already processed, i.e. we have saved /// corresponding included candidates. - last_observed_blocks: LruCache, + last_observed_blocks: LruMap, /// Maps included candidate hashes to one or more relay block heights and hashes. /// These correspond to all the relay blocks which marked a candidate as included, /// and are needed to apply reversions in case a dispute is concluded against the @@ -202,7 +196,7 @@ impl ChainScraper { let mut s = Self { included_candidates: candidates::ScrapedCandidates::new(), backed_candidates: candidates::ScrapedCandidates::new(), - last_observed_blocks: LruCache::new(LRU_OBSERVED_BLOCKS_CAPACITY), + last_observed_blocks: LruMap::new(ByLength::new(LRU_OBSERVED_BLOCKS_CAPACITY)), inclusions: Inclusions::new(), }; let update = @@ -288,7 +282,7 @@ impl ChainScraper { }, } - self.last_observed_blocks.put(activated.hash, ()); + self.last_observed_blocks.insert(activated.hash, ()); Ok(scraped_updates) } diff --git a/polkadot/node/core/runtime-api/Cargo.toml b/polkadot/node/core/runtime-api/Cargo.toml index 1a74ccdf73df..de165ebcc5c9 100644 --- a/polkadot/node/core/runtime-api/Cargo.toml +++ b/polkadot/node/core/runtime-api/Cargo.toml @@ -8,7 +8,7 @@ license.workspace = true [dependencies] futures = "0.3.21" gum = { package = "tracing-gum", path = "../../gum" } -lru = "0.11.0" +schnellru = "0.2.1" sp-consensus-babe = { path = "../../../../substrate/primitives/consensus/babe" } diff --git a/polkadot/node/core/runtime-api/src/cache.rs b/polkadot/node/core/runtime-api/src/cache.rs index 26aaf3fb6ec8..cd22f37ddee4 100644 --- a/polkadot/node/core/runtime-api/src/cache.rs +++ b/polkadot/node/core/runtime-api/src/cache.rs @@ -14,9 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use std::{collections::btree_map::BTreeMap, num::NonZeroUsize}; +use std::collections::btree_map::BTreeMap; -use lru::LruCache; +use schnellru::{ByLength, LruMap}; use sp_consensus_babe::Epoch; use polkadot_primitives::{ @@ -32,77 +32,74 @@ use polkadot_primitives::{ /// much if finality stalls (we only query state for unfinalized blocks + maybe latest finalized). /// In any case, a cache is an optimization. We should avoid a situation where having a large cache /// leads to OOM or puts pressure on other important stuff like PVF execution/preparation. -const DEFAULT_CACHE_CAP: NonZeroUsize = match NonZeroUsize::new(128) { - Some(cap) => cap, - None => panic!("lru capacity must be non-zero"), -}; +const DEFAULT_CACHE_CAP: u32 = 128; pub(crate) struct RequestResultCache { - authorities: LruCache>, - validators: LruCache>, - validator_groups: LruCache>, GroupRotationInfo)>, - availability_cores: LruCache>, + authorities: LruMap>, + validators: LruMap>, + validator_groups: LruMap>, GroupRotationInfo)>, + availability_cores: LruMap>, persisted_validation_data: - LruCache<(Hash, ParaId, OccupiedCoreAssumption), Option>, + LruMap<(Hash, ParaId, OccupiedCoreAssumption), Option>, assumed_validation_data: - LruCache<(ParaId, Hash), Option<(PersistedValidationData, ValidationCodeHash)>>, - check_validation_outputs: LruCache<(Hash, ParaId, CandidateCommitments), bool>, - session_index_for_child: LruCache, - validation_code: LruCache<(Hash, ParaId, OccupiedCoreAssumption), Option>, - validation_code_by_hash: LruCache>, - candidate_pending_availability: LruCache<(Hash, ParaId), Option>, - candidate_events: LruCache>, - session_executor_params: LruCache>, - session_info: LruCache, - dmq_contents: LruCache<(Hash, ParaId), Vec>>, + LruMap<(ParaId, Hash), Option<(PersistedValidationData, ValidationCodeHash)>>, + check_validation_outputs: LruMap<(Hash, ParaId, CandidateCommitments), bool>, + session_index_for_child: LruMap, + validation_code: LruMap<(Hash, ParaId, OccupiedCoreAssumption), Option>, + validation_code_by_hash: LruMap>, + candidate_pending_availability: LruMap<(Hash, ParaId), Option>, + candidate_events: LruMap>, + session_executor_params: LruMap>, + session_info: LruMap, + dmq_contents: LruMap<(Hash, ParaId), Vec>>, inbound_hrmp_channels_contents: - LruCache<(Hash, ParaId), BTreeMap>>>, - current_babe_epoch: LruCache, - on_chain_votes: LruCache>, - pvfs_require_precheck: LruCache>, + LruMap<(Hash, ParaId), BTreeMap>>>, + current_babe_epoch: LruMap, + on_chain_votes: LruMap>, + pvfs_require_precheck: LruMap>, validation_code_hash: - LruCache<(Hash, ParaId, OccupiedCoreAssumption), Option>, - version: LruCache, - disputes: LruCache)>>, + LruMap<(Hash, ParaId, OccupiedCoreAssumption), Option>, + version: LruMap, + disputes: LruMap)>>, unapplied_slashes: - LruCache>, + LruMap>, key_ownership_proof: - LruCache<(Hash, ValidatorId), Option>, + LruMap<(Hash, ValidatorId), Option>, - staging_para_backing_state: LruCache<(Hash, ParaId), Option>, - staging_async_backing_params: LruCache, + staging_para_backing_state: LruMap<(Hash, ParaId), Option>, + staging_async_backing_params: LruMap, } impl Default for RequestResultCache { fn default() -> Self { Self { - authorities: LruCache::new(DEFAULT_CACHE_CAP), - validators: LruCache::new(DEFAULT_CACHE_CAP), - validator_groups: LruCache::new(DEFAULT_CACHE_CAP), - availability_cores: LruCache::new(DEFAULT_CACHE_CAP), - persisted_validation_data: LruCache::new(DEFAULT_CACHE_CAP), - assumed_validation_data: LruCache::new(DEFAULT_CACHE_CAP), - check_validation_outputs: LruCache::new(DEFAULT_CACHE_CAP), - session_index_for_child: LruCache::new(DEFAULT_CACHE_CAP), - validation_code: LruCache::new(DEFAULT_CACHE_CAP), - validation_code_by_hash: LruCache::new(DEFAULT_CACHE_CAP), - candidate_pending_availability: LruCache::new(DEFAULT_CACHE_CAP), - candidate_events: LruCache::new(DEFAULT_CACHE_CAP), - session_executor_params: LruCache::new(DEFAULT_CACHE_CAP), - session_info: LruCache::new(DEFAULT_CACHE_CAP), - dmq_contents: LruCache::new(DEFAULT_CACHE_CAP), - inbound_hrmp_channels_contents: LruCache::new(DEFAULT_CACHE_CAP), - current_babe_epoch: LruCache::new(DEFAULT_CACHE_CAP), - on_chain_votes: LruCache::new(DEFAULT_CACHE_CAP), - pvfs_require_precheck: LruCache::new(DEFAULT_CACHE_CAP), - validation_code_hash: LruCache::new(DEFAULT_CACHE_CAP), - version: LruCache::new(DEFAULT_CACHE_CAP), - disputes: LruCache::new(DEFAULT_CACHE_CAP), - unapplied_slashes: LruCache::new(DEFAULT_CACHE_CAP), - key_ownership_proof: LruCache::new(DEFAULT_CACHE_CAP), - - staging_para_backing_state: LruCache::new(DEFAULT_CACHE_CAP), - staging_async_backing_params: LruCache::new(DEFAULT_CACHE_CAP), + authorities: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + validators: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + validator_groups: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + availability_cores: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + persisted_validation_data: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + assumed_validation_data: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + check_validation_outputs: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + session_index_for_child: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + validation_code: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + validation_code_by_hash: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + candidate_pending_availability: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + candidate_events: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + session_executor_params: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + session_info: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + dmq_contents: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + inbound_hrmp_channels_contents: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + current_babe_epoch: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + on_chain_votes: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + pvfs_require_precheck: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + validation_code_hash: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + version: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + disputes: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + unapplied_slashes: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + key_ownership_proof: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + + staging_para_backing_state: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), + staging_async_backing_params: LruMap::new(ByLength::new(DEFAULT_CACHE_CAP)), } } } @@ -112,7 +109,7 @@ impl RequestResultCache { &mut self, relay_parent: &Hash, ) -> Option<&Vec> { - self.authorities.get(relay_parent) + self.authorities.get(relay_parent).map(|v| &*v) } pub(crate) fn cache_authorities( @@ -120,22 +117,22 @@ impl RequestResultCache { relay_parent: Hash, authorities: Vec, ) { - self.authorities.put(relay_parent, authorities); + self.authorities.insert(relay_parent, authorities); } pub(crate) fn validators(&mut self, relay_parent: &Hash) -> Option<&Vec> { - self.validators.get(relay_parent) + self.validators.get(relay_parent).map(|v| &*v) } pub(crate) fn cache_validators(&mut self, relay_parent: Hash, validators: Vec) { - self.validators.put(relay_parent, validators); + self.validators.insert(relay_parent, validators); } pub(crate) fn validator_groups( &mut self, relay_parent: &Hash, ) -> Option<&(Vec>, GroupRotationInfo)> { - self.validator_groups.get(relay_parent) + self.validator_groups.get(relay_parent).map(|v| &*v) } pub(crate) fn cache_validator_groups( @@ -143,22 +140,22 @@ impl RequestResultCache { relay_parent: Hash, groups: (Vec>, GroupRotationInfo), ) { - self.validator_groups.put(relay_parent, groups); + self.validator_groups.insert(relay_parent, groups); } pub(crate) fn availability_cores(&mut self, relay_parent: &Hash) -> Option<&Vec> { - self.availability_cores.get(relay_parent) + self.availability_cores.get(relay_parent).map(|v| &*v) } pub(crate) fn cache_availability_cores(&mut self, relay_parent: Hash, cores: Vec) { - self.availability_cores.put(relay_parent, cores); + self.availability_cores.insert(relay_parent, cores); } pub(crate) fn persisted_validation_data( &mut self, key: (Hash, ParaId, OccupiedCoreAssumption), ) -> Option<&Option> { - self.persisted_validation_data.get(&key) + self.persisted_validation_data.get(&key).map(|v| &*v) } pub(crate) fn cache_persisted_validation_data( @@ -166,14 +163,14 @@ impl RequestResultCache { key: (Hash, ParaId, OccupiedCoreAssumption), data: Option, ) { - self.persisted_validation_data.put(key, data); + self.persisted_validation_data.insert(key, data); } pub(crate) fn assumed_validation_data( &mut self, key: (Hash, ParaId, Hash), ) -> Option<&Option<(PersistedValidationData, ValidationCodeHash)>> { - self.assumed_validation_data.get(&(key.1, key.2)) + self.assumed_validation_data.get(&(key.1, key.2)).map(|v| &*v) } pub(crate) fn cache_assumed_validation_data( @@ -181,14 +178,14 @@ impl RequestResultCache { key: (ParaId, Hash), data: Option<(PersistedValidationData, ValidationCodeHash)>, ) { - self.assumed_validation_data.put(key, data); + self.assumed_validation_data.insert(key, data); } pub(crate) fn check_validation_outputs( &mut self, key: (Hash, ParaId, CandidateCommitments), ) -> Option<&bool> { - self.check_validation_outputs.get(&key) + self.check_validation_outputs.get(&key).map(|v| &*v) } pub(crate) fn cache_check_validation_outputs( @@ -196,11 +193,11 @@ impl RequestResultCache { key: (Hash, ParaId, CandidateCommitments), value: bool, ) { - self.check_validation_outputs.put(key, value); + self.check_validation_outputs.insert(key, value); } pub(crate) fn session_index_for_child(&mut self, relay_parent: &Hash) -> Option<&SessionIndex> { - self.session_index_for_child.get(relay_parent) + self.session_index_for_child.get(relay_parent).map(|v| &*v) } pub(crate) fn cache_session_index_for_child( @@ -208,14 +205,14 @@ impl RequestResultCache { relay_parent: Hash, index: SessionIndex, ) { - self.session_index_for_child.put(relay_parent, index); + self.session_index_for_child.insert(relay_parent, index); } pub(crate) fn validation_code( &mut self, key: (Hash, ParaId, OccupiedCoreAssumption), ) -> Option<&Option> { - self.validation_code.get(&key) + self.validation_code.get(&key).map(|v| &*v) } pub(crate) fn cache_validation_code( @@ -223,7 +220,7 @@ impl RequestResultCache { key: (Hash, ParaId, OccupiedCoreAssumption), value: Option, ) { - self.validation_code.put(key, value); + self.validation_code.insert(key, value); } // the actual key is `ValidationCodeHash` (`Hash` is ignored), @@ -232,7 +229,7 @@ impl RequestResultCache { &mut self, key: (Hash, ValidationCodeHash), ) -> Option<&Option> { - self.validation_code_by_hash.get(&key.1) + self.validation_code_by_hash.get(&key.1).map(|v| &*v) } pub(crate) fn cache_validation_code_by_hash( @@ -240,14 +237,14 @@ impl RequestResultCache { key: ValidationCodeHash, value: Option, ) { - self.validation_code_by_hash.put(key, value); + self.validation_code_by_hash.insert(key, value); } pub(crate) fn candidate_pending_availability( &mut self, key: (Hash, ParaId), ) -> Option<&Option> { - self.candidate_pending_availability.get(&key) + self.candidate_pending_availability.get(&key).map(|v| &*v) } pub(crate) fn cache_candidate_pending_availability( @@ -255,11 +252,11 @@ impl RequestResultCache { key: (Hash, ParaId), value: Option, ) { - self.candidate_pending_availability.put(key, value); + self.candidate_pending_availability.insert(key, value); } pub(crate) fn candidate_events(&mut self, relay_parent: &Hash) -> Option<&Vec> { - self.candidate_events.get(relay_parent) + self.candidate_events.get(relay_parent).map(|v| &*v) } pub(crate) fn cache_candidate_events( @@ -267,22 +264,22 @@ impl RequestResultCache { relay_parent: Hash, events: Vec, ) { - self.candidate_events.put(relay_parent, events); + self.candidate_events.insert(relay_parent, events); } pub(crate) fn session_info(&mut self, key: SessionIndex) -> Option<&SessionInfo> { - self.session_info.get(&key) + self.session_info.get(&key).map(|v| &*v) } pub(crate) fn cache_session_info(&mut self, key: SessionIndex, value: SessionInfo) { - self.session_info.put(key, value); + self.session_info.insert(key, value); } pub(crate) fn session_executor_params( &mut self, session_index: SessionIndex, ) -> Option<&Option> { - self.session_executor_params.get(&session_index) + self.session_executor_params.get(&session_index).map(|v| &*v) } pub(crate) fn cache_session_executor_params( @@ -290,14 +287,14 @@ impl RequestResultCache { session_index: SessionIndex, value: Option, ) { - self.session_executor_params.put(session_index, value); + self.session_executor_params.insert(session_index, value); } pub(crate) fn dmq_contents( &mut self, key: (Hash, ParaId), ) -> Option<&Vec>> { - self.dmq_contents.get(&key) + self.dmq_contents.get(&key).map(|v| &*v) } pub(crate) fn cache_dmq_contents( @@ -305,14 +302,14 @@ impl RequestResultCache { key: (Hash, ParaId), value: Vec>, ) { - self.dmq_contents.put(key, value); + self.dmq_contents.insert(key, value); } pub(crate) fn inbound_hrmp_channels_contents( &mut self, key: (Hash, ParaId), ) -> Option<&BTreeMap>>> { - self.inbound_hrmp_channels_contents.get(&key) + self.inbound_hrmp_channels_contents.get(&key).map(|v| &*v) } pub(crate) fn cache_inbound_hrmp_channel_contents( @@ -320,22 +317,22 @@ impl RequestResultCache { key: (Hash, ParaId), value: BTreeMap>>, ) { - self.inbound_hrmp_channels_contents.put(key, value); + self.inbound_hrmp_channels_contents.insert(key, value); } pub(crate) fn current_babe_epoch(&mut self, relay_parent: &Hash) -> Option<&Epoch> { - self.current_babe_epoch.get(relay_parent) + self.current_babe_epoch.get(relay_parent).map(|v| &*v) } pub(crate) fn cache_current_babe_epoch(&mut self, relay_parent: Hash, epoch: Epoch) { - self.current_babe_epoch.put(relay_parent, epoch); + self.current_babe_epoch.insert(relay_parent, epoch); } pub(crate) fn on_chain_votes( &mut self, relay_parent: &Hash, ) -> Option<&Option> { - self.on_chain_votes.get(relay_parent) + self.on_chain_votes.get(relay_parent).map(|v| &*v) } pub(crate) fn cache_on_chain_votes( @@ -343,14 +340,14 @@ impl RequestResultCache { relay_parent: Hash, scraped: Option, ) { - self.on_chain_votes.put(relay_parent, scraped); + self.on_chain_votes.insert(relay_parent, scraped); } pub(crate) fn pvfs_require_precheck( &mut self, relay_parent: &Hash, ) -> Option<&Vec> { - self.pvfs_require_precheck.get(relay_parent) + self.pvfs_require_precheck.get(relay_parent).map(|v| &*v) } pub(crate) fn cache_pvfs_require_precheck( @@ -358,14 +355,14 @@ impl RequestResultCache { relay_parent: Hash, pvfs: Vec, ) { - self.pvfs_require_precheck.put(relay_parent, pvfs); + self.pvfs_require_precheck.insert(relay_parent, pvfs); } pub(crate) fn validation_code_hash( &mut self, key: (Hash, ParaId, OccupiedCoreAssumption), ) -> Option<&Option> { - self.validation_code_hash.get(&key) + self.validation_code_hash.get(&key).map(|v| &*v) } pub(crate) fn cache_validation_code_hash( @@ -373,22 +370,22 @@ impl RequestResultCache { key: (Hash, ParaId, OccupiedCoreAssumption), value: Option, ) { - self.validation_code_hash.put(key, value); + self.validation_code_hash.insert(key, value); } pub(crate) fn version(&mut self, relay_parent: &Hash) -> Option<&u32> { - self.version.get(relay_parent) + self.version.get(relay_parent).map(|v| &*v) } pub(crate) fn cache_version(&mut self, key: Hash, value: u32) { - self.version.put(key, value); + self.version.insert(key, value); } pub(crate) fn disputes( &mut self, relay_parent: &Hash, ) -> Option<&Vec<(SessionIndex, CandidateHash, DisputeState)>> { - self.disputes.get(relay_parent) + self.disputes.get(relay_parent).map(|v| &*v) } pub(crate) fn cache_disputes( @@ -396,14 +393,14 @@ impl RequestResultCache { relay_parent: Hash, value: Vec<(SessionIndex, CandidateHash, DisputeState)>, ) { - self.disputes.put(relay_parent, value); + self.disputes.insert(relay_parent, value); } pub(crate) fn unapplied_slashes( &mut self, relay_parent: &Hash, ) -> Option<&Vec<(SessionIndex, CandidateHash, vstaging::slashing::PendingSlashes)>> { - self.unapplied_slashes.get(relay_parent) + self.unapplied_slashes.get(relay_parent).map(|v| &*v) } pub(crate) fn cache_unapplied_slashes( @@ -411,14 +408,14 @@ impl RequestResultCache { relay_parent: Hash, value: Vec<(SessionIndex, CandidateHash, vstaging::slashing::PendingSlashes)>, ) { - self.unapplied_slashes.put(relay_parent, value); + self.unapplied_slashes.insert(relay_parent, value); } pub(crate) fn key_ownership_proof( &mut self, key: (Hash, ValidatorId), ) -> Option<&Option> { - self.key_ownership_proof.get(&key) + self.key_ownership_proof.get(&key).map(|v| &*v) } pub(crate) fn cache_key_ownership_proof( @@ -426,7 +423,7 @@ impl RequestResultCache { key: (Hash, ValidatorId), value: Option, ) { - self.key_ownership_proof.put(key, value); + self.key_ownership_proof.insert(key, value); } // This request is never cached, hence always returns `None`. @@ -441,7 +438,7 @@ impl RequestResultCache { &mut self, key: (Hash, ParaId), ) -> Option<&Option> { - self.staging_para_backing_state.get(&key) + self.staging_para_backing_state.get(&key).map(|v| &*v) } pub(crate) fn cache_staging_para_backing_state( @@ -449,14 +446,14 @@ impl RequestResultCache { key: (Hash, ParaId), value: Option, ) { - self.staging_para_backing_state.put(key, value); + self.staging_para_backing_state.insert(key, value); } pub(crate) fn staging_async_backing_params( &mut self, key: &Hash, ) -> Option<&vstaging::AsyncBackingParams> { - self.staging_async_backing_params.get(key) + self.staging_async_backing_params.get(key).map(|v| &*v) } pub(crate) fn cache_staging_async_backing_params( @@ -464,7 +461,7 @@ impl RequestResultCache { key: Hash, value: vstaging::AsyncBackingParams, ) { - self.staging_async_backing_params.put(key, value); + self.staging_async_backing_params.insert(key, value); } } diff --git a/polkadot/node/network/availability-distribution/Cargo.toml b/polkadot/node/network/availability-distribution/Cargo.toml index b81145688b69..60fe8fb9bd78 100644 --- a/polkadot/node/network/availability-distribution/Cargo.toml +++ b/polkadot/node/network/availability-distribution/Cargo.toml @@ -20,7 +20,7 @@ sp-keystore = { path = "../../../../substrate/primitives/keystore" } thiserror = "1.0.31" rand = "0.8.5" derive_more = "0.99.17" -lru = "0.11.0" +schnellru = "0.2.1" fatality = "0.0.6" [dev-dependencies] diff --git a/polkadot/node/network/availability-distribution/src/requester/session_cache.rs b/polkadot/node/network/availability-distribution/src/requester/session_cache.rs index e9311fb22038..8a48e19c2827 100644 --- a/polkadot/node/network/availability-distribution/src/requester/session_cache.rs +++ b/polkadot/node/network/availability-distribution/src/requester/session_cache.rs @@ -14,10 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -use std::{collections::HashSet, num::NonZeroUsize}; +use std::collections::HashSet; -use lru::LruCache; use rand::{seq::SliceRandom, thread_rng}; +use schnellru::{ByLength, LruMap}; use polkadot_node_subsystem::overseer; use polkadot_node_subsystem_util::runtime::RuntimeInfo; @@ -37,7 +37,7 @@ pub struct SessionCache { /// Note: Performance of fetching is really secondary here, but we need to ensure we are going /// to get any existing cache entry, before fetching new information, as we should not mess up /// the order of validators in `SessionInfo::validator_groups`. - session_info_cache: LruCache, + session_info_cache: LruMap, } /// Localized session information, tailored for the needs of availability distribution. @@ -83,7 +83,7 @@ impl SessionCache { pub fn new() -> Self { SessionCache { // We need to cache the current and the last session the most: - session_info_cache: LruCache::new(NonZeroUsize::new(2).unwrap()), + session_info_cache: LruMap::new(ByLength::new(2)), } } @@ -115,7 +115,7 @@ impl SessionCache { gum::trace!(target: LOG_TARGET, session_index, "Calling `with_info`"); let r = with_info(&info); gum::trace!(target: LOG_TARGET, session_index, "Storing session info in lru!"); - self.session_info_cache.put(session_index, info); + self.session_info_cache.insert(session_index, info); Ok(Some(r)) } else { Ok(None) @@ -142,7 +142,7 @@ impl SessionCache { /// will be put at the beginning of the group. pub fn report_bad(&mut self, report: BadValidators) -> Result<()> { let available_sessions = self.session_info_cache.iter().map(|(k, _)| *k).collect(); - let session = self.session_info_cache.get_mut(&report.session_index).ok_or( + let session = self.session_info_cache.get(&report.session_index).ok_or( Error::NoSuchCachedSession { available_sessions, missing_session: report.session_index, diff --git a/polkadot/node/network/availability-recovery/Cargo.toml b/polkadot/node/network/availability-recovery/Cargo.toml index 9dc4d05353ed..d6d79d3fc24d 100644 --- a/polkadot/node/network/availability-recovery/Cargo.toml +++ b/polkadot/node/network/availability-recovery/Cargo.toml @@ -7,7 +7,7 @@ license.workspace = true [dependencies] futures = "0.3.21" -lru = "0.11.0" +schnellru = "0.2.1" rand = "0.8.5" fatality = "0.0.6" thiserror = "1.0.31" diff --git a/polkadot/node/network/availability-recovery/src/lib.rs b/polkadot/node/network/availability-recovery/src/lib.rs index fb0cdb720571..99f42f4bf9fe 100644 --- a/polkadot/node/network/availability-recovery/src/lib.rs +++ b/polkadot/node/network/availability-recovery/src/lib.rs @@ -35,8 +35,8 @@ use futures::{ stream::{FuturesUnordered, StreamExt}, task::{Context, Poll}, }; -use lru::LruCache; use rand::seq::SliceRandom; +use schnellru::{ByLength, LruMap}; use fatality::Nested; use polkadot_erasure_coding::{ @@ -82,10 +82,7 @@ const LOG_TARGET: &str = "parachain::availability-recovery"; const N_PARALLEL: usize = 50; // Size of the LRU cache where we keep recovered data. -const LRU_SIZE: NonZeroUsize = match NonZeroUsize::new(16) { - Some(cap) => cap, - None => panic!("Availability-recovery cache size must be non-zero."), -}; +const LRU_SIZE: u32 = 16; const COST_INVALID_REQUEST: Rep = Rep::CostMajor("Peer sent unparsable request"); @@ -927,7 +924,7 @@ struct State { live_block: (BlockNumber, Hash), /// An LRU cache of recently recovered data. - availability_lru: LruCache, + availability_lru: LruMap, } impl Default for State { @@ -935,7 +932,7 @@ impl Default for State { Self { ongoing_recoveries: FuturesUnordered::new(), live_block: (0, Hash::default()), - availability_lru: LruCache::new(LRU_SIZE), + availability_lru: LruMap::new(ByLength::new(LRU_SIZE)), } } } @@ -1152,7 +1149,7 @@ async fn query_chunk_size( #[overseer::contextbounds(AvailabilityRecovery, prefix = self::overseer)] impl AvailabilityRecoverySubsystem { - /// Create a new instance of `AvailabilityRecoverySubsystem` which never requests the + /// Create a new instance of `AvailabilityRecoverySubsystem` which never requests the /// `AvailabilityStoreSubsystem` subsystem. pub fn with_availability_store_skip( req_receiver: IncomingRequestReceiver, @@ -1334,7 +1331,7 @@ impl AvailabilityRecoverySubsystem { output = state.ongoing_recoveries.select_next_some() => { if let Some((candidate_hash, result)) = output { if let Ok(recovery) = CachedRecovery::try_from(result) { - state.availability_lru.put(candidate_hash, recovery); + state.availability_lru.insert(candidate_hash, recovery); } } } diff --git a/polkadot/node/network/dispute-distribution/Cargo.toml b/polkadot/node/network/dispute-distribution/Cargo.toml index 24f597bacadd..24ae7ba25bc5 100644 --- a/polkadot/node/network/dispute-distribution/Cargo.toml +++ b/polkadot/node/network/dispute-distribution/Cargo.toml @@ -22,7 +22,7 @@ sp-application-crypto = { path = "../../../../substrate/primitives/application-c sp-keystore = { path = "../../../../substrate/primitives/keystore" } thiserror = "1.0.31" fatality = "0.0.6" -lru = "0.11.0" +schnellru = "0.2.1" indexmap = "1.9.1" [dev-dependencies] diff --git a/polkadot/node/network/dispute-distribution/src/lib.rs b/polkadot/node/network/dispute-distribution/src/lib.rs index ad99bc41fa64..071dc3c3343b 100644 --- a/polkadot/node/network/dispute-distribution/src/lib.rs +++ b/polkadot/node/network/dispute-distribution/src/lib.rs @@ -24,7 +24,7 @@ //! The sender is responsible for getting our vote out, see [`sender`]. The receiver handles //! incoming [`DisputeRequest`]s and offers spam protection, see [`receiver`]. -use std::{num::NonZeroUsize, time::Duration}; +use std::time::Duration; use futures::{channel::mpsc, FutureExt, StreamExt, TryFutureExt}; @@ -165,8 +165,7 @@ where ) -> Self { let runtime = RuntimeInfo::new_with_config(runtime::Config { keystore: Some(keystore), - session_cache_lru_size: NonZeroUsize::new(DISPUTE_WINDOW.get() as usize) - .expect("Dispute window can not be 0; qed"), + session_cache_lru_size: DISPUTE_WINDOW.get(), }); let (tx, sender_rx) = NestingSender::new_root(1); let disputes_sender = DisputeSender::new(tx, metrics.clone()); diff --git a/polkadot/node/network/dispute-distribution/src/receiver/mod.rs b/polkadot/node/network/dispute-distribution/src/receiver/mod.rs index 827a77281ccb..2b3fc45983a9 100644 --- a/polkadot/node/network/dispute-distribution/src/receiver/mod.rs +++ b/polkadot/node/network/dispute-distribution/src/receiver/mod.rs @@ -15,7 +15,6 @@ // along with Polkadot. If not, see . use std::{ - num::NonZeroUsize, pin::Pin, task::{Context, Poll}, time::Duration, @@ -161,8 +160,7 @@ where ) -> Self { let runtime = RuntimeInfo::new_with_config(runtime::Config { keystore: None, - session_cache_lru_size: NonZeroUsize::new(DISPUTE_WINDOW.get() as usize) - .expect("Dispute window can not be 0; qed"), + session_cache_lru_size: DISPUTE_WINDOW.get(), }); Self { runtime, diff --git a/polkadot/node/overseer/Cargo.toml b/polkadot/node/overseer/Cargo.toml index 577b12e2620e..982ccc7ff245 100644 --- a/polkadot/node/overseer/Cargo.toml +++ b/polkadot/node/overseer/Cargo.toml @@ -18,7 +18,7 @@ polkadot-node-metrics = { path = "../metrics" } polkadot-primitives = { path = "../../primitives" } orchestra = "0.0.5" gum = { package = "tracing-gum", path = "../gum" } -lru = "0.11.0" +schnellru = "0.2.1" sp-core = { path = "../../../substrate/primitives/core" } async-trait = "0.1.57" tikv-jemalloc-ctl = { version = "0.5.0", optional = true } diff --git a/polkadot/node/overseer/src/dummy.rs b/polkadot/node/overseer/src/dummy.rs index 79daba140676..fea96e5dbab7 100644 --- a/polkadot/node/overseer/src/dummy.rs +++ b/polkadot/node/overseer/src/dummy.rs @@ -19,9 +19,9 @@ use crate::{ Overseer, OverseerMetrics, OverseerSignal, OverseerSubsystemContext, SpawnGlue, KNOWN_LEAVES_CACHE_SIZE, }; -use lru::LruCache; use orchestra::{FromOrchestra, SpawnedSubsystem, Subsystem, SubsystemContext}; use polkadot_node_subsystem_types::{errors::SubsystemError, messages::*}; +use schnellru::{ByLength, LruMap}; // Generated dummy messages use crate::messages::*; @@ -193,7 +193,7 @@ where .activation_external_listeners(Default::default()) .span_per_active_leaf(Default::default()) .active_leaves(Default::default()) - .known_leaves(LruCache::new(KNOWN_LEAVES_CACHE_SIZE)) + .known_leaves(LruMap::new(ByLength::new(KNOWN_LEAVES_CACHE_SIZE))) .spawner(SpawnGlue(spawner)) .metrics(metrics) .supports_parachains(supports_parachains); diff --git a/polkadot/node/overseer/src/lib.rs b/polkadot/node/overseer/src/lib.rs index 5655a3ef79c1..b8643982323c 100644 --- a/polkadot/node/overseer/src/lib.rs +++ b/polkadot/node/overseer/src/lib.rs @@ -62,14 +62,13 @@ use std::{ collections::{hash_map, HashMap}, fmt::{self, Debug}, - num::NonZeroUsize, pin::Pin, sync::Arc, time::Duration, }; use futures::{channel::oneshot, future::BoxFuture, select, Future, FutureExt, StreamExt}; -use lru::LruCache; +use schnellru::LruMap; use client::{BlockImportNotification, BlockchainEvents, FinalityNotification}; use polkadot_primitives::{Block, BlockNumber, Hash}; @@ -113,10 +112,7 @@ pub use orchestra::{ /// Store 2 days worth of blocks, not accounting for forks, /// in the LRU cache. Assumes a 6-second block time. -pub const KNOWN_LEAVES_CACHE_SIZE: NonZeroUsize = match NonZeroUsize::new(2 * 24 * 3600 / 6) { - Some(cap) => cap, - None => panic!("Known leaves cache size must be non-zero"), -}; +pub const KNOWN_LEAVES_CACHE_SIZE: u32 = 2 * 24 * 3600 / 6; #[cfg(any(target_os = "linux", feature = "jemalloc-allocator"))] mod memory_stats; @@ -632,7 +628,7 @@ pub struct Overseer { pub supports_parachains: SupportsParachains, /// An LRU cache for keeping track of relay-chain heads that have already been seen. - pub known_leaves: LruCache, + pub known_leaves: LruMap, /// Various Prometheus metrics. pub metrics: OverseerMetrics, @@ -880,9 +876,10 @@ where let span = Arc::new(span); self.span_per_active_leaf.insert(*hash, span.clone()); - let status = if let Some(_) = self.known_leaves.put(*hash, ()) { + let status = if self.known_leaves.get(hash).is_some() { LeafStatus::Stale } else { + self.known_leaves.insert(*hash, ()); LeafStatus::Fresh }; diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs index 392781783319..4cebc23ad31d 100644 --- a/polkadot/node/primitives/src/lib.rs +++ b/polkadot/node/primitives/src/lib.rs @@ -22,7 +22,7 @@ #![deny(missing_docs)] -use std::{num::NonZeroUsize, pin::Pin}; +use std::pin::Pin; use bounded_vec::BoundedVec; use futures::Future; @@ -143,12 +143,6 @@ impl SessionWindowSize { } } -impl From for NonZeroUsize { - fn from(value: SessionWindowSize) -> Self { - NonZeroUsize::new(value.get() as usize).expect("SessionWindowSize can't be 0. qed.") - } -} - /// The cumulative weight of a block in a fork-choice rule. pub type BlockWeight = u32; diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index f58f4abca362..58be7a885357 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -86,7 +86,7 @@ parity-db = { version = "0.4.8", optional = true } codec = { package = "parity-scale-codec", version = "3.6.1" } async-trait = "0.1.57" -lru = "0.11.0" +schnellru = "0.2.1" log = "0.4.17" is_executable = "1.0.1" diff --git a/polkadot/node/service/src/overseer.rs b/polkadot/node/service/src/overseer.rs index cb6b80eb83c8..1c49577508f6 100644 --- a/polkadot/node/service/src/overseer.rs +++ b/polkadot/node/service/src/overseer.rs @@ -19,7 +19,6 @@ use polkadot_node_subsystem_types::DefaultSubsystemClient; use sc_transaction_pool_api::OffchainTransactionPoolFactory; use sp_core::traits::SpawnNamed; -use lru::LruCache; use polkadot_availability_distribution::IncomingRequestReceivers; use polkadot_node_core_approval_voting::Config as ApprovalVotingConfig; use polkadot_node_core_av_store::Config as AvailabilityConfig; @@ -41,6 +40,7 @@ use polkadot_overseer::{ metrics::Metrics as OverseerMetrics, InitializedOverseerBuilder, MetricsTrait, Overseer, OverseerConnector, OverseerHandle, SpawnGlue, }; +use schnellru::{ByLength, LruMap}; use polkadot_primitives::runtime_api::ParachainHost; use sc_authority_discovery::Service as AuthorityDiscoveryService; @@ -344,7 +344,7 @@ where .span_per_active_leaf(Default::default()) .active_leaves(Default::default()) .supports_parachains(runtime_api_client) - .known_leaves(LruCache::new(KNOWN_LEAVES_CACHE_SIZE)) + .known_leaves(LruMap::new(ByLength::new(KNOWN_LEAVES_CACHE_SIZE))) .metrics(metrics) .spawner(spawner); diff --git a/polkadot/node/subsystem-util/Cargo.toml b/polkadot/node/subsystem-util/Cargo.toml index a7c802a8ca87..87a823da9090 100644 --- a/polkadot/node/subsystem-util/Cargo.toml +++ b/polkadot/node/subsystem-util/Cargo.toml @@ -19,7 +19,7 @@ thiserror = "1.0.31" fatality = "0.0.6" gum = { package = "tracing-gum", path = "../gum" } derive_more = "0.99.17" -lru = "0.11.0" +schnellru = "0.2.1" polkadot-node-subsystem = { path = "../subsystem" } polkadot-node-jaeger = { path = "../jaeger" } diff --git a/polkadot/node/subsystem-util/src/runtime/mod.rs b/polkadot/node/subsystem-util/src/runtime/mod.rs index 1f5641e3ea95..a044a64e93a0 100644 --- a/polkadot/node/subsystem-util/src/runtime/mod.rs +++ b/polkadot/node/subsystem-util/src/runtime/mod.rs @@ -16,9 +16,7 @@ //! Convenient interface to runtime information. -use std::num::NonZeroUsize; - -use lru::LruCache; +use schnellru::{ByLength, LruMap}; use parity_scale_codec::Encode; use sp_application_crypto::AppCrypto; @@ -58,7 +56,7 @@ pub struct Config { pub keystore: Option, /// How many sessions should we keep in the cache? - pub session_cache_lru_size: NonZeroUsize, + pub session_cache_lru_size: u32, } /// Caching of session info. @@ -69,10 +67,10 @@ pub struct RuntimeInfo { /// /// We query this up to a 100 times per block, so caching it here without roundtrips over the /// overseer seems sensible. - session_index_cache: LruCache, + session_index_cache: LruMap, /// Look up cached sessions by `SessionIndex`. - session_info_cache: LruCache, + session_info_cache: LruMap, /// Key store for determining whether we are a validator and what `ValidatorIndex` we have. keystore: Option, @@ -101,7 +99,7 @@ impl Default for Config { Self { keystore: None, // Usually we need to cache the current and the last session. - session_cache_lru_size: NonZeroUsize::new(2).expect("2 is larger than 0; qed"), + session_cache_lru_size: 2, } } } @@ -115,11 +113,8 @@ impl RuntimeInfo { /// Create with more elaborate configuration options. pub fn new_with_config(cfg: Config) -> Self { Self { - session_index_cache: LruCache::new( - cfg.session_cache_lru_size - .max(NonZeroUsize::new(10).expect("10 is larger than 0; qed")), - ), - session_info_cache: LruCache::new(cfg.session_cache_lru_size), + session_index_cache: LruMap::new(ByLength::new(cfg.session_cache_lru_size.max(10))), + session_info_cache: LruMap::new(ByLength::new(cfg.session_cache_lru_size)), keystore: cfg.keystore, } } @@ -139,7 +134,7 @@ impl RuntimeInfo { None => { let index = recv_runtime(request_session_index_for_child(parent, sender).await).await?; - self.session_index_cache.put(parent, index); + self.session_index_cache.insert(parent, index); Ok(index) }, } @@ -172,7 +167,7 @@ impl RuntimeInfo { where Sender: SubsystemSender, { - if !self.session_info_cache.contains(&session_index) { + if self.session_info_cache.get(&session_index).is_none() { let session_info = recv_runtime(request_session_info(parent, session_index, sender).await) .await? @@ -181,7 +176,7 @@ impl RuntimeInfo { let full_info = ExtendedSessionInfo { session_info, validator_info }; - self.session_info_cache.put(session_index, full_info); + self.session_info_cache.insert(session_index, full_info); } Ok(self .session_info_cache diff --git a/polkadot/roadmap/implementers-guide/src/node/availability/availability-recovery.md b/polkadot/roadmap/implementers-guide/src/node/availability/availability-recovery.md index 48fb0fb1ca19..ac733c1ce918 100644 --- a/polkadot/roadmap/implementers-guide/src/node/availability/availability-recovery.md +++ b/polkadot/roadmap/implementers-guide/src/node/availability/availability-recovery.md @@ -30,7 +30,7 @@ struct State { /// A recent block hash for which state should be available. live_block_hash: Hash, // An LRU cache of recently recovered data. - availability_lru: LruCache>, + availability_lru: LruMap>, } /// This is a future, which concludes either when a response is received from the recovery tasks, diff --git a/polkadot/roadmap/implementers-guide/src/node/disputes/dispute-coordinator.md b/polkadot/roadmap/implementers-guide/src/node/disputes/dispute-coordinator.md index 7692491fde1f..f8bfe6506aa5 100644 --- a/polkadot/roadmap/implementers-guide/src/node/disputes/dispute-coordinator.md +++ b/polkadot/roadmap/implementers-guide/src/node/disputes/dispute-coordinator.md @@ -9,7 +9,7 @@ In particular the dispute-coordinator is responsible for: - Ensuring that the node is able to raise a dispute in case an invalid candidate is found during approval checking. -- Ensuring that backing and approval votes will be recorded on chain. With these +- Ensuring that backing and approval votes will be recorded on chain. With these votes on chain we can be certain that appropriate targets for slashing will be available for concluded disputes. Also, scraping these votes during a dispute is necessary for critical spam prevention measures. @@ -678,7 +678,7 @@ struct State { // It can be a `Vec` if the need to track more arises. error: Option, /// Latest relay blocks that have been successfully scraped. - last_scraped_blocks: LruCache, + last_scraped_blocks: LruMap, } ```