Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .config/lychee.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ exclude = [
"github.com/ChainSafe/forest",
# Maybe temporarily down with 404, but it blocks the CI
"filecoin.io/slack",
# Bot protection
"crates.io",
Comment thread
LesnyRumcajs marked this conversation as resolved.
]
timeout = 30
max_retries = 6
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@

### Breaking

- [#7073](https://github.com/ChainSafe/forest/pull/7073): Replaced the underlying cache engine across the node. The eviction policy is no longer strict LRU — it is now CLOCK-PRO via [`quick_cache`](https://crates.io/crates/quick_cache), which is scan-resistant and typically gives higher hit rates on chain workloads. The Prometheus metric names `lru_cache_hit_total` and `lru_cache_miss_total` are renamed to `cache_hit_total` and `cache_miss_total`. **Operators must update dashboards, alert rules, and recording rules** that reference the old names. Label set (`kind="..."`) is unchanged.

### Added

- [#6012](https://github.com/ChainSafe/forest/issues/6012): Stricter validation of address arguments in `forest-wallet` subcommands.
Expand Down
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ zstd = "0.13"

# optional dependencies
console-subscriber = { version = "0.5", features = ["parking_lot"], optional = true }
quick_cache = "0.6"
Comment thread
hanabi1224 marked this conversation as resolved.
sqlx = { version = "0.8", default-features = false, features = ["sqlite", "runtime-tokio", "macros"], optional = true }
tikv-jemallocator = { version = "0.6", optional = true }
tracing-loki = { version = "0.2", default-features = false, features = ["compat-0-2-1", "rustls"], optional = true }
Expand Down
19 changes: 8 additions & 11 deletions src/beacon/drand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use super::{
use crate::prelude::*;
use crate::shim::clock::ChainEpoch;
use crate::shim::version::NetworkVersion;
use crate::utils::cache::SizeTrackingLruCache;
use crate::utils::cache::SizeTrackingCache;
use crate::utils::misc::env::is_env_truthy;
use crate::utils::net::global_http_client;
use ambassador::{Delegate, delegatable_trait};
Expand Down Expand Up @@ -223,7 +223,7 @@ pub struct DrandBeacon {
fil_round_time: u64,

/// Keeps track of verified beacon entries.
verified_beacons: SizeTrackingLruCache<u64, BeaconEntry>,
verified_beacons: SizeTrackingCache<u64, Arc<BeaconEntry>>,
}

impl DrandBeacon {
Expand All @@ -241,16 +241,12 @@ impl DrandBeacon {
drand_gen_time: config.chain_info.genesis_time as u64,
fil_round_time: interval,
fil_gen_time: genesis_ts,
verified_beacons: SizeTrackingLruCache::new_with_metrics(
"verified_beacons",
CACHE_SIZE,
),
verified_beacons: SizeTrackingCache::new_with_metrics("verified_beacons", CACHE_SIZE),
}
}

fn is_verified(&self, entry: &BeaconEntry) -> bool {
let cache = self.verified_beacons.cache().read();
cache.peek(&entry.round()) == Some(entry)
self.verified_beacons.peek_cloned(&entry.round()).as_deref() == Some(entry)
}
}

Expand Down Expand Up @@ -318,17 +314,18 @@ impl Beacon for DrandBeacon {
tracing::warn!(%cap, validated_len=%validated.len(), "verified_beacons.cap() is too small");
}
for entry in validated {
self.verified_beacons.push(entry.round(), entry.clone());
self.verified_beacons
.push(entry.round(), Arc::new(entry.clone()));
}
}

Ok(is_valid)
}

async fn entry(&self, round: u64) -> anyhow::Result<BeaconEntry> {
let cached: Option<BeaconEntry> = self.verified_beacons.peek_cloned(&round);
let cached = self.verified_beacons.peek_cloned(&round);
match cached {
Some(cached_entry) => Ok(cached_entry),
Some(cached_entry) => Ok(Arc::unwrap_or_clone(cached_entry)),
None => {
async fn fetch_entry_from_url(
url: impl reqwest::IntoUrl,
Expand Down
6 changes: 3 additions & 3 deletions src/chain/store/chain_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::{
message::{ChainMessage, SignedMessage},
};
use crate::{db::EthMappingsStoreExt, rpc::chain::PathChange};
use crate::{fil_cns, utils::cache::SizeTrackingLruCache};
use crate::{fil_cns, utils::cache::SizeTrackingCache};
use crate::{
interpreter::{BlockMessages, VMTrace},
rpc::chain::PathChanges,
Expand Down Expand Up @@ -590,13 +590,13 @@ where
/// use-cases. This cache is intended to be used with a complementary function;
/// [`messages_for_tipset_with_cache`].
pub struct MessagesInTipsetCache {
cache: SizeTrackingLruCache<TipsetKey, Arc<Vec<ChainMessage>>>,
cache: SizeTrackingCache<TipsetKey, Arc<Vec<ChainMessage>>>,
}

impl MessagesInTipsetCache {
pub fn new(capacity: NonZeroUsize) -> Self {
Self {
cache: SizeTrackingLruCache::new_with_metrics("msg_in_tipset", capacity),
cache: SizeTrackingCache::new_with_metrics("msg_in_tipset", capacity),
}
}

Expand Down
10 changes: 5 additions & 5 deletions src/chain/store/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ use crate::db::{DbImpl, EthMappingsStore as _};
use crate::metrics;
use crate::prelude::*;
use crate::shim::clock::ChainEpoch;
use crate::utils::cache::SizeTrackingLruCache;
use crate::utils::cache::SizeTrackingCache;
use nonzero_ext::nonzero;
use num::Integer;

const DEFAULT_TIPSET_CACHE_SIZE: NonZeroUsize = nonzero!(2880_usize);

type TipsetCache = SizeTrackingLruCache<TipsetKey, Tipset>;
type TipsetCache = SizeTrackingCache<TipsetKey, Tipset>;

type IsTipsetFinalizedFn = Arc<dyn Fn(&Tipset) -> bool + Send + Sync>;

Expand Down Expand Up @@ -53,7 +53,7 @@ pub enum ResolveNullTipset {
impl ChainIndex {
pub fn new(db: impl Into<DbImpl>) -> Self {
let db = db.into();
let ts_cache = SizeTrackingLruCache::new_with_metrics("tipset", DEFAULT_TIPSET_CACHE_SIZE);
let ts_cache = SizeTrackingCache::new_with_metrics("tipset", DEFAULT_TIPSET_CACHE_SIZE);
Self {
ts_cache,
db,
Expand Down Expand Up @@ -81,7 +81,7 @@ impl ChainIndex {
if !cache_disabled()
&& let Some(ts) = self.ts_cache.get_cloned(tsk)
{
metrics::LRU_CACHE_HIT
metrics::CACHE_HIT
.get_or_create(&metrics::values::TIPSET)
.inc();
return Ok(Some(ts));
Expand All @@ -92,7 +92,7 @@ impl ChainIndex {
&& let Some(ts) = &ts_opt
{
self.ts_cache.push(tsk.clone(), ts.clone());
metrics::LRU_CACHE_MISS
metrics::CACHE_MISS
.get_or_create(&metrics::values::TIPSET)
.inc();
}
Expand Down
14 changes: 7 additions & 7 deletions src/chain_sync/bad_block_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::num::NonZeroUsize;
use nonzero_ext::nonzero;

use crate::prelude::*;
use crate::utils::{cache::SizeTrackingLruCache, get_size};
use crate::utils::{cache::SizeTrackingCache, get_size};

/// Default capacity for CID caches (32768 entries).
/// That's about 4 MiB.
Expand All @@ -17,7 +17,7 @@ const DEFAULT_CID_CACHE_CAPACITY: NonZeroUsize = nonzero!(1usize << 15);
/// work.
#[derive(Debug)]
pub struct BadBlockCache {
cache: SizeTrackingLruCache<get_size::CidWrapper, ()>,
cache: SizeTrackingCache<get_size::CidWrapper, ()>,
}

impl Default for BadBlockCache {
Expand All @@ -37,7 +37,7 @@ impl ShallowClone for BadBlockCache {
impl BadBlockCache {
pub fn new(cap: NonZeroUsize) -> Self {
Self {
cache: SizeTrackingLruCache::new_with_metrics("bad_block", cap),
cache: SizeTrackingCache::new_with_metrics("bad_block", cap),
}
}

Expand All @@ -49,19 +49,19 @@ impl BadBlockCache {
/// Returns `Some` if the block CID is in bad block cache.
/// This function does not update the head position of the `Cid` key.
pub fn peek(&self, c: &Cid) -> Option<()> {
self.cache.peek_cloned(&(*c).into())
self.cache.peek_cloned(&get_size::CidWrapper::from(*c))
}

pub fn clear(&self) {
self.cache.clear()
}
}

/// Thread-safe LRU cache for tracking recently seen gossip block CIDs.
/// Thread-safe cache for tracking recently seen gossip block CIDs.
/// Used to de-duplicate gossip blocks before expensive message fetching.
#[derive(Debug)]
pub struct SeenBlockCache {
cache: SizeTrackingLruCache<get_size::CidWrapper, ()>,
cache: SizeTrackingCache<get_size::CidWrapper, ()>,
}

impl ShallowClone for SeenBlockCache {
Expand All @@ -81,7 +81,7 @@ impl Default for SeenBlockCache {
impl SeenBlockCache {
pub fn new(cap: NonZeroUsize) -> Self {
Self {
cache: SizeTrackingLruCache::new_with_metrics("seen_gossip_block", cap),
cache: SizeTrackingCache::new_with_metrics("seen_gossip_block", cap),
}
}

Expand Down
12 changes: 6 additions & 6 deletions src/db/blockstore_with_read_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use cid::Cid;
use fvm_ipld_blockstore::Blockstore;
use std::sync::atomic::{self, AtomicUsize};

use crate::utils::{cache::SizeTrackingLruCache, get_size};
use crate::utils::{cache::SizeTrackingCache, get_size};

#[auto_impl::auto_impl(&, Arc)]
pub trait BlockstoreReadCache {
Expand All @@ -14,15 +14,15 @@ pub trait BlockstoreReadCache {
fn put(&self, k: Cid, block: Vec<u8>);
}

pub type LruBlockstoreReadCache = SizeTrackingLruCache<get_size::CidWrapper, Vec<u8>>;
pub type DefaultBlockstoreReadCache = SizeTrackingCache<get_size::CidWrapper, Vec<u8>>;

impl BlockstoreReadCache for SizeTrackingLruCache<get_size::CidWrapper, Vec<u8>> {
impl BlockstoreReadCache for SizeTrackingCache<get_size::CidWrapper, Vec<u8>> {
fn get(&self, k: &Cid) -> Option<Vec<u8>> {
self.get_cloned(&(*k).into())
self.get_cloned(&get_size::CidWrapper::from(*k))
}

fn put(&self, k: Cid, block: Vec<u8>) {
self.push(k.into(), block);
self.push(get_size::CidWrapper::from(k), block);
}
}

Expand Down Expand Up @@ -126,7 +126,7 @@ mod tests {
mem_db.put_keyed(&key, &record).unwrap();
records.push((key, record));
}
let cache = Arc::new(LruBlockstoreReadCache::new_without_metrics_registry(
let cache = Arc::new(DefaultBlockstoreReadCache::new_without_metrics_registry(
"test_blockstore_read_cache",
CACHE_SIZE.try_into().unwrap(),
));
Expand Down
2 changes: 1 addition & 1 deletion src/db/car/forest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
//! Looking up a block uses an [`index::Reader`] to find
//! the right z-frame. The frame is then decoded and each block is linearly
//! scanned until a match is found. Decoded (and scanned) z-frames are stored in
//! a lru-cache for faster repeat retrievals.
//! a cache for faster repeat retrievals.
//!
//! `forest.car.zst` files are backward compatible with Lotus (and all other
//! tools that consume compressed CAR files). All Forest-specifc information is
Expand Down
Loading
Loading