diff --git a/Cargo.lock b/Cargo.lock index 339f650ad6ba..8581ec64c59f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4027,15 +4027,6 @@ dependencies = [ "parity-util-mem", ] -[[package]] -name = "memory-lru" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce95ae042940bad7e312857b929ee3d11b8f799a80cb7b9c7ec5125516906395" -dependencies = [ - "lru", -] - [[package]] name = "memory_units" version = "0.4.0" @@ -6531,8 +6522,7 @@ name = "polkadot-node-core-runtime-api" version = "0.9.31" dependencies = [ "futures", - "memory-lru", - "parity-util-mem", + "lru", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", diff --git a/node/core/runtime-api/Cargo.toml b/node/core/runtime-api/Cargo.toml index ff7ea662603c..8c941228cd95 100644 --- a/node/core/runtime-api/Cargo.toml +++ b/node/core/runtime-api/Cargo.toml @@ -7,8 +7,7 @@ edition = "2021" [dependencies] futures = "0.3.21" gum = { package = "tracing-gum", path = "../../gum" } -memory-lru = "0.1.1" -parity-util-mem = { version = "0.12.0", default-features = false } +lru = "0.8" sp-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/node/core/runtime-api/src/cache.rs b/node/core/runtime-api/src/cache.rs index 0fe9b74dc86d..d202b46d0da3 100644 --- a/node/core/runtime-api/src/cache.rs +++ b/node/core/runtime-api/src/cache.rs @@ -14,10 +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; +use std::{collections::btree_map::BTreeMap, num::NonZeroUsize}; -use memory_lru::{MemoryLruCache, ResidentSize}; -use parity_util_mem::{MallocSizeOf, MallocSizeOfExt}; +use lru::LruCache; use sp_consensus_babe::Epoch; use polkadot_primitives::v2::{ @@ -28,126 +27,67 @@ use polkadot_primitives::v2::{ ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, }; -const AUTHORITIES_CACHE_SIZE: usize = 128 * 1024; -const VALIDATORS_CACHE_SIZE: usize = 64 * 1024; -const VALIDATOR_GROUPS_CACHE_SIZE: usize = 64 * 1024; -const AVAILABILITY_CORES_CACHE_SIZE: usize = 64 * 1024; -const PERSISTED_VALIDATION_DATA_CACHE_SIZE: usize = 64 * 1024; -const ASSUMED_VALIDATION_DATA_CACHE_SIZE: usize = 64 * 1024; -const CHECK_VALIDATION_OUTPUTS_CACHE_SIZE: usize = 64 * 1024; -const SESSION_INDEX_FOR_CHILD_CACHE_SIZE: usize = 64 * 1024; -const VALIDATION_CODE_CACHE_SIZE: usize = 10 * 1024 * 1024; -const CANDIDATE_PENDING_AVAILABILITY_CACHE_SIZE: usize = 64 * 1024; -const CANDIDATE_EVENTS_CACHE_SIZE: usize = 64 * 1024; -const SESSION_INFO_CACHE_SIZE: usize = 64 * 1024; -const DMQ_CONTENTS_CACHE_SIZE: usize = 64 * 1024; -const INBOUND_HRMP_CHANNELS_CACHE_SIZE: usize = 64 * 1024; -const CURRENT_BABE_EPOCH_CACHE_SIZE: usize = 64 * 1024; -const ON_CHAIN_VOTES_CACHE_SIZE: usize = 3 * 1024; -const PVFS_REQUIRE_PRECHECK_SIZE: usize = 1024; -const VALIDATION_CODE_HASH_CACHE_SIZE: usize = 64 * 1024; -const VERSION_CACHE_SIZE: usize = 4 * 1024; -const DISPUTES_CACHE_SIZE: usize = 64 * 1024; - -struct ResidentSizeOf(T); - -impl ResidentSize for ResidentSizeOf { - fn resident_size(&self) -> usize { - std::mem::size_of::() + self.0.malloc_size_of() - } -} - -struct DoesNotAllocate(T); - -impl ResidentSize for DoesNotAllocate { - fn resident_size(&self) -> usize { - std::mem::size_of::() - } -} - -// this is an ugly workaround for `AuthorityDiscoveryId` -// not implementing `MallocSizeOf` -struct VecOfDoesNotAllocate(Vec); - -impl ResidentSize for VecOfDoesNotAllocate { - fn resident_size(&self) -> usize { - std::mem::size_of::() * self.0.capacity() - } -} +/// For consistency we have the same capacity for all caches. We use 128 as we'll only need that +/// 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"), +}; pub(crate) struct RequestResultCache { - authorities: MemoryLruCache>, - validators: MemoryLruCache>>, - validator_groups: - MemoryLruCache>, GroupRotationInfo)>>, - availability_cores: MemoryLruCache>>, - persisted_validation_data: MemoryLruCache< - (Hash, ParaId, OccupiedCoreAssumption), - ResidentSizeOf>, - >, - assumed_validation_data: MemoryLruCache< - (ParaId, Hash), - ResidentSizeOf>, - >, - check_validation_outputs: - MemoryLruCache<(Hash, ParaId, CandidateCommitments), ResidentSizeOf>, - session_index_for_child: MemoryLruCache>, - validation_code: MemoryLruCache< - (Hash, ParaId, OccupiedCoreAssumption), - ResidentSizeOf>, - >, - validation_code_by_hash: - MemoryLruCache>>, - candidate_pending_availability: - MemoryLruCache<(Hash, ParaId), ResidentSizeOf>>, - candidate_events: MemoryLruCache>>, - session_info: MemoryLruCache>, - dmq_contents: - MemoryLruCache<(Hash, ParaId), ResidentSizeOf>>>, - inbound_hrmp_channels_contents: MemoryLruCache< - (Hash, ParaId), - ResidentSizeOf>>>, - >, - current_babe_epoch: MemoryLruCache>, - on_chain_votes: MemoryLruCache>>, - pvfs_require_precheck: MemoryLruCache>>, - validation_code_hash: MemoryLruCache< - (Hash, ParaId, OccupiedCoreAssumption), - ResidentSizeOf>, - >, - version: MemoryLruCache>, - disputes: MemoryLruCache< - Hash, - ResidentSizeOf)>>, - >, + authorities: LruCache>, + validators: LruCache>, + validator_groups: LruCache>, GroupRotationInfo)>, + availability_cores: LruCache>, + persisted_validation_data: + LruCache<(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_info: LruCache, + dmq_contents: LruCache<(Hash, ParaId), Vec>>, + inbound_hrmp_channels_contents: + LruCache<(Hash, ParaId), BTreeMap>>>, + current_babe_epoch: LruCache, + on_chain_votes: LruCache>, + pvfs_require_precheck: LruCache>, + validation_code_hash: + LruCache<(Hash, ParaId, OccupiedCoreAssumption), Option>, + version: LruCache, + disputes: LruCache)>>, } impl Default for RequestResultCache { fn default() -> Self { Self { - authorities: MemoryLruCache::new(AUTHORITIES_CACHE_SIZE), - validators: MemoryLruCache::new(VALIDATORS_CACHE_SIZE), - validator_groups: MemoryLruCache::new(VALIDATOR_GROUPS_CACHE_SIZE), - availability_cores: MemoryLruCache::new(AVAILABILITY_CORES_CACHE_SIZE), - persisted_validation_data: MemoryLruCache::new(PERSISTED_VALIDATION_DATA_CACHE_SIZE), - assumed_validation_data: MemoryLruCache::new(ASSUMED_VALIDATION_DATA_CACHE_SIZE), - check_validation_outputs: MemoryLruCache::new(CHECK_VALIDATION_OUTPUTS_CACHE_SIZE), - session_index_for_child: MemoryLruCache::new(SESSION_INDEX_FOR_CHILD_CACHE_SIZE), - validation_code: MemoryLruCache::new(VALIDATION_CODE_CACHE_SIZE), - validation_code_by_hash: MemoryLruCache::new(VALIDATION_CODE_CACHE_SIZE), - candidate_pending_availability: MemoryLruCache::new( - CANDIDATE_PENDING_AVAILABILITY_CACHE_SIZE, - ), - candidate_events: MemoryLruCache::new(CANDIDATE_EVENTS_CACHE_SIZE), - session_info: MemoryLruCache::new(SESSION_INFO_CACHE_SIZE), - dmq_contents: MemoryLruCache::new(DMQ_CONTENTS_CACHE_SIZE), - inbound_hrmp_channels_contents: MemoryLruCache::new(INBOUND_HRMP_CHANNELS_CACHE_SIZE), - current_babe_epoch: MemoryLruCache::new(CURRENT_BABE_EPOCH_CACHE_SIZE), - on_chain_votes: MemoryLruCache::new(ON_CHAIN_VOTES_CACHE_SIZE), - pvfs_require_precheck: MemoryLruCache::new(PVFS_REQUIRE_PRECHECK_SIZE), - validation_code_hash: MemoryLruCache::new(VALIDATION_CODE_HASH_CACHE_SIZE), - version: MemoryLruCache::new(VERSION_CACHE_SIZE), - disputes: MemoryLruCache::new(DISPUTES_CACHE_SIZE), + 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_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), } } } @@ -157,7 +97,7 @@ impl RequestResultCache { &mut self, relay_parent: &Hash, ) -> Option<&Vec> { - self.authorities.get(relay_parent).map(|v| &v.0) + self.authorities.get(relay_parent) } pub(crate) fn cache_authorities( @@ -165,22 +105,22 @@ impl RequestResultCache { relay_parent: Hash, authorities: Vec, ) { - self.authorities.insert(relay_parent, VecOfDoesNotAllocate(authorities)); + self.authorities.put(relay_parent, authorities); } pub(crate) fn validators(&mut self, relay_parent: &Hash) -> Option<&Vec> { - self.validators.get(relay_parent).map(|v| &v.0) + self.validators.get(relay_parent) } pub(crate) fn cache_validators(&mut self, relay_parent: Hash, validators: Vec) { - self.validators.insert(relay_parent, ResidentSizeOf(validators)); + self.validators.put(relay_parent, validators); } pub(crate) fn validator_groups( &mut self, relay_parent: &Hash, ) -> Option<&(Vec>, GroupRotationInfo)> { - self.validator_groups.get(relay_parent).map(|v| &v.0) + self.validator_groups.get(relay_parent) } pub(crate) fn cache_validator_groups( @@ -188,22 +128,22 @@ impl RequestResultCache { relay_parent: Hash, groups: (Vec>, GroupRotationInfo), ) { - self.validator_groups.insert(relay_parent, ResidentSizeOf(groups)); + self.validator_groups.put(relay_parent, groups); } pub(crate) fn availability_cores(&mut self, relay_parent: &Hash) -> Option<&Vec> { - self.availability_cores.get(relay_parent).map(|v| &v.0) + self.availability_cores.get(relay_parent) } pub(crate) fn cache_availability_cores(&mut self, relay_parent: Hash, cores: Vec) { - self.availability_cores.insert(relay_parent, ResidentSizeOf(cores)); + self.availability_cores.put(relay_parent, cores); } pub(crate) fn persisted_validation_data( &mut self, key: (Hash, ParaId, OccupiedCoreAssumption), ) -> Option<&Option> { - self.persisted_validation_data.get(&key).map(|v| &v.0) + self.persisted_validation_data.get(&key) } pub(crate) fn cache_persisted_validation_data( @@ -211,14 +151,14 @@ impl RequestResultCache { key: (Hash, ParaId, OccupiedCoreAssumption), data: Option, ) { - self.persisted_validation_data.insert(key, ResidentSizeOf(data)); + self.persisted_validation_data.put(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)).map(|v| &v.0) + self.assumed_validation_data.get(&(key.1, key.2)) } pub(crate) fn cache_assumed_validation_data( @@ -226,14 +166,14 @@ impl RequestResultCache { key: (ParaId, Hash), data: Option<(PersistedValidationData, ValidationCodeHash)>, ) { - self.assumed_validation_data.insert(key, ResidentSizeOf(data)); + self.assumed_validation_data.put(key, data); } pub(crate) fn check_validation_outputs( &mut self, key: (Hash, ParaId, CandidateCommitments), ) -> Option<&bool> { - self.check_validation_outputs.get(&key).map(|v| &v.0) + self.check_validation_outputs.get(&key) } pub(crate) fn cache_check_validation_outputs( @@ -241,11 +181,11 @@ impl RequestResultCache { key: (Hash, ParaId, CandidateCommitments), value: bool, ) { - self.check_validation_outputs.insert(key, ResidentSizeOf(value)); + self.check_validation_outputs.put(key, value); } pub(crate) fn session_index_for_child(&mut self, relay_parent: &Hash) -> Option<&SessionIndex> { - self.session_index_for_child.get(relay_parent).map(|v| &v.0) + self.session_index_for_child.get(relay_parent) } pub(crate) fn cache_session_index_for_child( @@ -253,14 +193,14 @@ impl RequestResultCache { relay_parent: Hash, index: SessionIndex, ) { - self.session_index_for_child.insert(relay_parent, ResidentSizeOf(index)); + self.session_index_for_child.put(relay_parent, index); } pub(crate) fn validation_code( &mut self, key: (Hash, ParaId, OccupiedCoreAssumption), ) -> Option<&Option> { - self.validation_code.get(&key).map(|v| &v.0) + self.validation_code.get(&key) } pub(crate) fn cache_validation_code( @@ -268,7 +208,7 @@ impl RequestResultCache { key: (Hash, ParaId, OccupiedCoreAssumption), value: Option, ) { - self.validation_code.insert(key, ResidentSizeOf(value)); + self.validation_code.put(key, value); } // the actual key is `ValidationCodeHash` (`Hash` is ignored), @@ -277,7 +217,7 @@ impl RequestResultCache { &mut self, key: (Hash, ValidationCodeHash), ) -> Option<&Option> { - self.validation_code_by_hash.get(&key.1).map(|v| &v.0) + self.validation_code_by_hash.get(&key.1) } pub(crate) fn cache_validation_code_by_hash( @@ -285,14 +225,14 @@ impl RequestResultCache { key: ValidationCodeHash, value: Option, ) { - self.validation_code_by_hash.insert(key, ResidentSizeOf(value)); + self.validation_code_by_hash.put(key, value); } pub(crate) fn candidate_pending_availability( &mut self, key: (Hash, ParaId), ) -> Option<&Option> { - self.candidate_pending_availability.get(&key).map(|v| &v.0) + self.candidate_pending_availability.get(&key) } pub(crate) fn cache_candidate_pending_availability( @@ -300,11 +240,11 @@ impl RequestResultCache { key: (Hash, ParaId), value: Option, ) { - self.candidate_pending_availability.insert(key, ResidentSizeOf(value)); + self.candidate_pending_availability.put(key, value); } pub(crate) fn candidate_events(&mut self, relay_parent: &Hash) -> Option<&Vec> { - self.candidate_events.get(relay_parent).map(|v| &v.0) + self.candidate_events.get(relay_parent) } pub(crate) fn cache_candidate_events( @@ -312,22 +252,22 @@ impl RequestResultCache { relay_parent: Hash, events: Vec, ) { - self.candidate_events.insert(relay_parent, ResidentSizeOf(events)); + self.candidate_events.put(relay_parent, events); } pub(crate) fn session_info(&mut self, key: SessionIndex) -> Option<&SessionInfo> { - self.session_info.get(&key).map(|v| &v.0) + self.session_info.get(&key) } pub(crate) fn cache_session_info(&mut self, key: SessionIndex, value: SessionInfo) { - self.session_info.insert(key, ResidentSizeOf(value)); + self.session_info.put(key, value); } pub(crate) fn dmq_contents( &mut self, key: (Hash, ParaId), ) -> Option<&Vec>> { - self.dmq_contents.get(&key).map(|v| &v.0) + self.dmq_contents.get(&key) } pub(crate) fn cache_dmq_contents( @@ -335,14 +275,14 @@ impl RequestResultCache { key: (Hash, ParaId), value: Vec>, ) { - self.dmq_contents.insert(key, ResidentSizeOf(value)); + self.dmq_contents.put(key, value); } pub(crate) fn inbound_hrmp_channels_contents( &mut self, key: (Hash, ParaId), ) -> Option<&BTreeMap>>> { - self.inbound_hrmp_channels_contents.get(&key).map(|v| &v.0) + self.inbound_hrmp_channels_contents.get(&key) } pub(crate) fn cache_inbound_hrmp_channel_contents( @@ -350,22 +290,22 @@ impl RequestResultCache { key: (Hash, ParaId), value: BTreeMap>>, ) { - self.inbound_hrmp_channels_contents.insert(key, ResidentSizeOf(value)); + self.inbound_hrmp_channels_contents.put(key, value); } pub(crate) fn current_babe_epoch(&mut self, relay_parent: &Hash) -> Option<&Epoch> { - self.current_babe_epoch.get(relay_parent).map(|v| &v.0) + self.current_babe_epoch.get(relay_parent) } pub(crate) fn cache_current_babe_epoch(&mut self, relay_parent: Hash, epoch: Epoch) { - self.current_babe_epoch.insert(relay_parent, DoesNotAllocate(epoch)); + self.current_babe_epoch.put(relay_parent, epoch); } pub(crate) fn on_chain_votes( &mut self, relay_parent: &Hash, ) -> Option<&Option> { - self.on_chain_votes.get(relay_parent).map(|v| &v.0) + self.on_chain_votes.get(relay_parent) } pub(crate) fn cache_on_chain_votes( @@ -373,14 +313,14 @@ impl RequestResultCache { relay_parent: Hash, scraped: Option, ) { - self.on_chain_votes.insert(relay_parent, ResidentSizeOf(scraped)); + self.on_chain_votes.put(relay_parent, scraped); } pub(crate) fn pvfs_require_precheck( &mut self, relay_parent: &Hash, ) -> Option<&Vec> { - self.pvfs_require_precheck.get(relay_parent).map(|v| &v.0) + self.pvfs_require_precheck.get(relay_parent) } pub(crate) fn cache_pvfs_require_precheck( @@ -388,14 +328,14 @@ impl RequestResultCache { relay_parent: Hash, pvfs: Vec, ) { - self.pvfs_require_precheck.insert(relay_parent, ResidentSizeOf(pvfs)) + self.pvfs_require_precheck.put(relay_parent, pvfs); } pub(crate) fn validation_code_hash( &mut self, key: (Hash, ParaId, OccupiedCoreAssumption), ) -> Option<&Option> { - self.validation_code_hash.get(&key).map(|v| &v.0) + self.validation_code_hash.get(&key) } pub(crate) fn cache_validation_code_hash( @@ -403,22 +343,22 @@ impl RequestResultCache { key: (Hash, ParaId, OccupiedCoreAssumption), value: Option, ) { - self.validation_code_hash.insert(key, ResidentSizeOf(value)); + self.validation_code_hash.put(key, value); } pub(crate) fn version(&mut self, relay_parent: &Hash) -> Option<&u32> { - self.version.get(&relay_parent).map(|v| &v.0) + self.version.get(relay_parent) } pub(crate) fn cache_version(&mut self, key: Hash, value: u32) { - self.version.insert(key, ResidentSizeOf(value)); + self.version.put(key, value); } pub(crate) fn disputes( &mut self, relay_parent: &Hash, ) -> Option<&Vec<(SessionIndex, CandidateHash, DisputeState)>> { - self.disputes.get(relay_parent).map(|v| &v.0) + self.disputes.get(relay_parent) } pub(crate) fn cache_disputes( @@ -426,7 +366,7 @@ impl RequestResultCache { relay_parent: Hash, value: Vec<(SessionIndex, CandidateHash, DisputeState)>, ) { - self.disputes.insert(relay_parent, ResidentSizeOf(value)); + self.disputes.put(relay_parent, value); } }