Use hashlink over lru for LruCache (#8911)

Use the `LruCache` implementation provided by `hashlink` instead of the current `lru` one.
This is mostly a 1-to-1 swap with only slight API incompatibilities.
I have decided to leave some config files which previously used `NonZeroUsize` but they may not be required anymore and could potentially switch to `usize`.


Co-Authored-By: Mac L <mjladson@pm.me>
This commit is contained in:
Mac L
2026-06-16 10:54:11 +04:00
committed by GitHub
parent 41dff2d965
commit e0ff3b5709
28 changed files with 166 additions and 192 deletions

View File

@@ -1,15 +1,13 @@
use crate::{BeaconChain, BeaconChainError, BeaconChainTypes};
use hashlink::lru_cache::LruCache;
use itertools::process_results;
use lru::LruCache;
use parking_lot::Mutex;
use std::num::NonZeroUsize;
use std::time::Duration;
use tracing::debug;
use types::Hash256;
use types::new_non_zero_usize;
const BLOCK_ROOT_CACHE_LIMIT: NonZeroUsize = new_non_zero_usize(512);
const LOOKUP_LIMIT: NonZeroUsize = new_non_zero_usize(8);
const BLOCK_ROOT_CACHE_LIMIT: usize = 512;
const LOOKUP_LIMIT: usize = 8;
const METRICS_TIMEOUT: Duration = Duration::from_millis(100);
/// Cache for rejecting attestations to blocks from before finalization.
@@ -49,13 +47,13 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
let mut cache = self.pre_finalization_block_cache.cache.lock();
// Check the cache to see if we already know this pre-finalization block root.
if cache.block_roots.contains(&block_root) {
if cache.block_roots.contains_key(&block_root) {
return Ok(true);
}
// Avoid repeating the disk lookup for blocks that are already subject to a network lookup.
// Sync will take care of de-duplicating the single block lookups.
if cache.in_progress_lookups.contains(&block_root) {
if cache.in_progress_lookups.contains_key(&block_root) {
return Ok(false);
}
@@ -68,19 +66,19 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
.map_err(BeaconChainError::BeaconStateError)
})?;
if is_recent_finalized_block {
cache.block_roots.put(block_root, ());
cache.block_roots.insert(block_root, ());
return Ok(true);
}
// 2. Check on disk.
if self.store.get_blinded_block(&block_root)?.is_some() {
cache.block_roots.put(block_root, ());
cache.block_roots.insert(block_root, ());
return Ok(true);
}
// 3. Check the network with a single block lookup.
cache.in_progress_lookups.put(block_root, ());
if cache.in_progress_lookups.len() == LOOKUP_LIMIT.get() {
cache.in_progress_lookups.insert(block_root, ());
if cache.in_progress_lookups.len() == LOOKUP_LIMIT {
// NOTE: we expect this to occur sometimes if a lot of blocks that we look up fail to be
// imported for reasons other than being pre-finalization. The cache will eventually
// self-repair in this case by replacing old entries with new ones until all the failed
@@ -95,8 +93,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
pub fn pre_finalization_block_rejected(&self, block_root: Hash256) {
// Future requests can know that this block is invalid without having to look it up again.
let mut cache = self.pre_finalization_block_cache.cache.lock();
cache.in_progress_lookups.pop(&block_root);
cache.block_roots.put(block_root, ());
cache.in_progress_lookups.remove(&block_root);
cache.block_roots.insert(block_root, ());
}
}
@@ -104,11 +102,11 @@ impl PreFinalizationBlockCache {
pub fn block_processed(&self, block_root: Hash256) {
// Future requests will find this block in fork choice, so no need to cache it in the
// ongoing lookup cache any longer.
self.cache.lock().in_progress_lookups.pop(&block_root);
self.cache.lock().in_progress_lookups.remove(&block_root);
}
pub fn contains(&self, block_root: Hash256) -> bool {
self.cache.lock().block_roots.contains(&block_root)
self.cache.lock().block_roots.contains_key(&block_root)
}
pub fn metrics(&self) -> Option<(usize, usize)> {