Skip to content

Commit 20a9c8d

Browse files
authored
Merge branch 'main' into elmattic/api-run-subcommand
2 parents 706ef61 + 6b53690 commit 20a9c8d

23 files changed

Lines changed: 185 additions & 59 deletions

File tree

.clippy.toml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ reason = """use `crate::utils::new_uuid_v4` instead."""
4444
path = "tempfile::NamedTempFile::new"
4545
reason = """The temporary files created by this method are not persistable if the temporary directory lives on a different filesystem than the target directory. While it is valid in other contexts (if not persisting files), it was misused many times and so we are banning it. Consider using `tempfile::NamedTempFile::new_in` or `tempfile::NamedTempFile::Builder"""
4646

47+
[[disallowed-methods]]
48+
path = "lru::LruCache::new"
49+
reason = """Use SizeTrackingLruCache instead."""
50+
51+
[[disallowed-methods]]
52+
path = "lru::LruCache::with_hasher"
53+
reason = """Use SizeTrackingLruCache instead."""
54+
4755
[[disallowed-methods]]
4856
path = "lru::LruCache::unbounded"
49-
reason = """Avoid unbounded lru cache for potential memory leak"""
57+
reason = """Avoid unbounded lru cache for potential memory leak, use SizeTrackingLruCache instead."""
58+
59+
[[disallowed-methods]]
60+
path = "lru::LruCache::unbounded_with_hasher"
61+
reason = """Avoid unbounded lru cache for potential memory leak, use SizeTrackingLruCache instead."""

interop-tests/tests/dhat_get_size_beacon_entry.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ fn test_get_size_beacon_entry() {
4949
assert_eq!(v.capacity(), v.len());
5050
dhat::assert_eq!(
5151
stats.curr_bytes,
52-
size_of::<BeaconEntry>() * v.capacity() + 60
52+
size_of::<BeaconEntry>() * v.capacity() + inner_bytes
5353
);
5454
dhat::assert_eq!(stats.curr_bytes, v.get_heap_size());
5555
}

src/beacon/drand.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ impl DrandBeacon {
262262
fil_round_time: interval,
263263
fil_gen_time: genesis_ts,
264264
verified_beacons: SizeTrackingLruCache::new_with_default_metrics_registry(
265-
"verified_beacons_cache".into(),
265+
"verified_beacons".into(),
266266
NonZeroUsize::new(CACHE_SIZE).expect("Infallible"),
267267
),
268268
}

src/blocks/election_proof.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::blocks::VRFProof;
55
use crate::shim::clock::BLOCKS_PER_EPOCH;
66
use crate::utils::encoding::blake2b_256;
77
use fvm_ipld_encoding::tuple::*;
8+
use get_size2::GetSize;
89
use num::{
910
BigInt, Integer,
1011
bigint::{ParseBigIntError, Sign},
@@ -134,7 +135,17 @@ impl Poiss {
134135
/// This is generated from hashing a partial ticket and using the hash to
135136
/// generate a value.
136137
#[derive(
137-
Clone, Debug, PartialEq, PartialOrd, Eq, Default, Ord, Serialize_tuple, Deserialize_tuple, Hash,
138+
Clone,
139+
Debug,
140+
PartialEq,
141+
PartialOrd,
142+
Eq,
143+
Default,
144+
Ord,
145+
Serialize_tuple,
146+
Deserialize_tuple,
147+
Hash,
148+
GetSize,
138149
)]
139150
pub struct ElectionProof {
140151
pub win_count: i64,

src/blocks/header.rs

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@ use crate::{
1414
address::Address, clock::ChainEpoch, crypto::Signature, econ::TokenAmount,
1515
sector::PoStProof, version::NetworkVersion,
1616
},
17-
utils::{encoding::blake2b_256, multihash::MultihashCode},
17+
utils::{encoding::blake2b_256, get_size::big_int_heap_size_helper, multihash::MultihashCode},
1818
};
1919
use cid::Cid;
2020
use fvm_ipld_blockstore::Blockstore;
2121
use fvm_ipld_encoding::CborStore as _;
2222
use fvm_ipld_encoding::tuple::*;
23+
use get_size2::GetSize;
2324
use multihash_derive::MultihashDigest as _;
2425
use num::BigInt;
2526
use serde::{Deserialize, Serialize};
@@ -197,11 +198,46 @@ impl RawBlockHeader {
197198
}
198199
}
199200

201+
// The derive macro does not compile for some reason
202+
impl GetSize for RawBlockHeader {
203+
fn get_heap_size(&self) -> usize {
204+
let Self {
205+
miner_address,
206+
ticket,
207+
election_proof,
208+
beacon_entries,
209+
winning_post_proof,
210+
parents,
211+
weight,
212+
epoch: _,
213+
state_root: _,
214+
message_receipts: _,
215+
messages: _,
216+
bls_aggregate,
217+
timestamp: _,
218+
signature,
219+
fork_signal: _,
220+
parent_base_fee,
221+
} = self;
222+
miner_address.get_heap_size()
223+
+ ticket.get_heap_size()
224+
+ election_proof.get_heap_size()
225+
+ beacon_entries.get_heap_size()
226+
+ winning_post_proof.get_heap_size()
227+
+ parents.get_heap_size()
228+
+ big_int_heap_size_helper(weight)
229+
+ bls_aggregate.get_heap_size()
230+
+ signature.get_heap_size()
231+
+ parent_base_fee.get_heap_size()
232+
}
233+
}
234+
200235
/// A [`RawBlockHeader`] which caches calls to [`RawBlockHeader::cid`] and [`RawBlockHeader::verify_signature_against`]
201236
#[cfg_attr(test, derive(Default))]
202-
#[derive(Debug)]
237+
#[derive(Debug, GetSize)]
203238
pub struct CachingBlockHeader {
204239
uncached: RawBlockHeader,
240+
#[get_size(ignore)]
205241
cid: OnceLock<Cid>,
206242
has_ever_been_verified_against_any_signature: AtomicBool,
207243
}

src/blocks/ticket.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,23 @@
33

44
use crate::blocks::VRFProof;
55
use fvm_ipld_encoding::tuple::*;
6+
use get_size2::GetSize;
67

78
/// A Ticket is a marker of a tick of the blockchain's clock. It is the source
89
/// of randomness for proofs of storage and leader election. It is generated
910
/// by the miner of a block using a `VRF` and a `VDF`.
1011
#[derive(
11-
Clone, Debug, PartialEq, Eq, Default, Serialize_tuple, Deserialize_tuple, Hash, PartialOrd, Ord,
12+
Clone,
13+
Debug,
14+
PartialEq,
15+
Eq,
16+
Default,
17+
Serialize_tuple,
18+
Deserialize_tuple,
19+
Hash,
20+
PartialOrd,
21+
Ord,
22+
GetSize,
1223
)]
1324
pub struct Ticket {
1425
/// A proof output by running a `VRF` on the `VDFResult` of the parent

src/blocks/tipset.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::{
1111
cid_collections::SmallCidNonEmptyVec,
1212
networks::{calibnet, mainnet},
1313
shim::clock::ChainEpoch,
14-
utils::cid::CidCborExt,
14+
utils::{cid::CidCborExt, get_size::nunny_vec_heap_size_helper},
1515
};
1616
use ahash::HashMap;
1717
use anyhow::Context as _;
@@ -146,9 +146,10 @@ impl IntoIterator for TipsetKey {
146146
///
147147
/// Represents non-null tipsets, see the documentation on [`crate::state_manager::apply_block_messages`]
148148
/// for more.
149-
#[derive(Clone, Debug)]
149+
#[derive(Clone, Debug, GetSize)]
150150
pub struct Tipset {
151151
/// Sorted
152+
#[get_size(size_fn = nunny_vec_heap_size_helper)]
152153
headers: NonEmpty<CachingBlockHeader>,
153154
// key is lazily initialized via `fn key()`.
154155
key: OnceLock<TipsetKey>,

src/blocks/vrf_proof.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0, MIT
33

44
use crate::utils::encoding::{blake2b_256, serde_byte_array};
5+
use get_size2::GetSize;
56
use serde::{Deserialize, Serialize};
67

78
/// The output from running a VRF proof.
@@ -25,3 +26,9 @@ impl VRFProof {
2526
blake2b_256(&self.0)
2627
}
2728
}
29+
30+
impl GetSize for VRFProof {
31+
fn get_heap_size(&self) -> usize {
32+
self.0.get_heap_size()
33+
}
34+
}

src/chain/store/chain_store.rs

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use super::{
66
index::{ChainIndex, ResolveNullTipset},
77
tipset_tracker::TipsetTracker,
88
};
9-
use crate::fil_cns;
109
use crate::interpreter::{BlockMessages, VMTrace};
1110
use crate::libp2p_bitswap::{BitswapStoreRead, BitswapStoreReadWrite};
1211
use crate::message::{ChainMessage, Message as MessageTrait, SignedMessage};
@@ -27,15 +26,15 @@ use crate::{
2726
chain_sync::metrics,
2827
db::{EthMappingsStore, EthMappingsStoreExt, IndicesStore, IndicesStoreExt},
2928
};
29+
use crate::{fil_cns, utils::cache::SizeTrackingLruCache};
3030
use ahash::{HashMap, HashMapExt, HashSet};
3131
use anyhow::Context as _;
3232
use cid::Cid;
3333
use fil_actors_shared::fvm_ipld_amt::Amtv0 as Amt;
3434
use fvm_ipld_blockstore::Blockstore;
3535
use fvm_ipld_encoding::CborStore;
3636
use itertools::Itertools;
37-
use lru::LruCache;
38-
use parking_lot::{Mutex, RwLock};
37+
use parking_lot::Mutex;
3938
use serde::{Serialize, de::DeserializeOwned};
4039
use std::{num::NonZeroUsize, sync::Arc};
4140
use tokio::sync::broadcast::{self, Sender as Publisher};
@@ -554,27 +553,28 @@ where
554553
/// use-cases. This cache is intended to be used with a complementary function;
555554
/// [`messages_for_tipset_with_cache`].
556555
pub struct MsgsInTipsetCache {
557-
cache: RwLock<LruCache<TipsetKey, Vec<ChainMessage>>>,
556+
cache: SizeTrackingLruCache<TipsetKey, Vec<ChainMessage>>,
558557
}
559558

560559
impl MsgsInTipsetCache {
561-
pub fn new(cap: usize) -> anyhow::Result<Self> {
562-
Ok(Self {
563-
cache: RwLock::new(LruCache::new(
564-
NonZeroUsize::new(cap).context("cache capacity must be greater than 0")?,
565-
)),
566-
})
560+
pub fn new(capacity: NonZeroUsize) -> Self {
561+
Self {
562+
cache: SizeTrackingLruCache::new_with_default_metrics_registry(
563+
"msg_in_tipset".into(),
564+
capacity,
565+
),
566+
}
567567
}
568568

569569
pub fn get(&self, key: &TipsetKey) -> Option<Vec<ChainMessage>> {
570-
self.cache.write().get(key).cloned()
570+
self.cache.get_cloned(key)
571571
}
572572

573573
pub fn get_or_insert_with<F>(&self, key: &TipsetKey, f: F) -> anyhow::Result<Vec<ChainMessage>>
574574
where
575575
F: FnOnce() -> anyhow::Result<Vec<ChainMessage>>,
576576
{
577-
if self.cache.read().contains(key) {
577+
if self.cache.contains(key) {
578578
Ok(self.get(key).expect("cache entry disappeared!"))
579579
} else {
580580
let v = f()?;
@@ -584,21 +584,23 @@ impl MsgsInTipsetCache {
584584
}
585585

586586
pub fn insert(&self, key: TipsetKey, value: Vec<ChainMessage>) {
587-
self.cache.write().put(key, value);
587+
self.cache.push(key, value);
588588
}
589589

590590
/// Reads the intended cache size for this process from the environment or uses the default.
591-
fn read_cache_size() -> usize {
591+
fn read_cache_size() -> NonZeroUsize {
592+
// Arbitrary number, can be adjusted
593+
const DEFAULT: NonZeroUsize = NonZeroUsize::new(100).expect("infallible");
592594
std::env::var("FOREST_MESSAGES_IN_TIPSET_CACHE_SIZE")
593595
.ok()
594596
.and_then(|s| s.parse().ok())
595-
.unwrap_or(100) // Arbitrary number, can be adjusted
597+
.unwrap_or(DEFAULT)
596598
}
597599
}
598600

599601
impl Default for MsgsInTipsetCache {
600602
fn default() -> Self {
601-
Self::new(Self::read_cache_size()).expect("failed to create default cache")
603+
Self::new(Self::read_cache_size())
602604
}
603605
}
604606

@@ -796,7 +798,7 @@ mod tests {
796798

797799
#[test]
798800
fn test_messages_in_tipset_cache() {
799-
let cache = MsgsInTipsetCache::new(2).unwrap();
801+
let cache = MsgsInTipsetCache::new(2.try_into().unwrap());
800802
let key1 = TipsetKey::from(nunny::vec![Cid::new_v1(
801803
DAG_CBOR,
802804
MultihashCode::Blake2b256.digest(&[1])

src/chain/store/index.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,21 @@ use crate::blocks::{Tipset, TipsetKey};
88
use crate::chain::Error;
99
use crate::metrics;
1010
use crate::shim::clock::ChainEpoch;
11+
use crate::utils::cache::SizeTrackingLruCache;
1112
use crate::utils::misc::env::is_env_truthy;
1213
use fvm_ipld_blockstore::Blockstore;
1314
use itertools::Itertools;
14-
use lru::LruCache;
1515
use nonzero_ext::nonzero;
16-
use parking_lot::Mutex;
1716

1817
const DEFAULT_TIPSET_CACHE_SIZE: NonZeroUsize = nonzero!(131072_usize);
1918

20-
type TipsetCache = Mutex<LruCache<TipsetKey, Arc<Tipset>>>;
19+
type TipsetCache = SizeTrackingLruCache<TipsetKey, Arc<Tipset>>;
2120

2221
/// Keeps look-back tipsets in cache at a given interval `skip_length` and can
2322
/// be used to look-back at the chain to retrieve an old tipset.
2423
pub struct ChainIndex<DB> {
2524
/// `Arc` reference tipset cache.
2625
ts_cache: TipsetCache,
27-
2826
/// `Blockstore` pointer needed to load tipsets from cold storage.
2927
pub db: DB,
3028
}
@@ -40,25 +38,27 @@ pub enum ResolveNullTipset {
4038

4139
impl<DB: Blockstore> ChainIndex<DB> {
4240
pub fn new(db: DB) -> Self {
43-
let ts_cache = Mutex::new(LruCache::new(DEFAULT_TIPSET_CACHE_SIZE));
41+
let ts_cache = SizeTrackingLruCache::new_with_default_metrics_registry(
42+
"tipset".into(),
43+
DEFAULT_TIPSET_CACHE_SIZE,
44+
);
4445
Self { ts_cache, db }
4546
}
4647

4748
/// Loads a tipset from memory given the tipset keys and cache. Semantically
4849
/// identical to [`Tipset::load`] but the result is cached.
4950
pub fn load_tipset(&self, tsk: &TipsetKey) -> Result<Option<Arc<Tipset>>, Error> {
50-
if !is_env_truthy("FOREST_TIPSET_CACHE_DISABLED")
51-
&& let Some(ts) = self.ts_cache.lock().get(tsk)
52-
{
51+
let cache_enabled = !is_env_truthy("FOREST_TIPSET_CACHE_DISABLED");
52+
if cache_enabled && let Some(ts) = self.ts_cache.get_cloned(tsk) {
5353
metrics::LRU_CACHE_HIT
5454
.get_or_create(&metrics::values::TIPSET)
5555
.inc();
56-
return Ok(Some(ts.clone()));
56+
return Ok(Some(ts));
5757
}
5858

5959
let ts_opt = Tipset::load(&self.db, tsk)?.map(Arc::new);
60-
if let Some(ts) = &ts_opt {
61-
self.ts_cache.lock().put(tsk.clone(), ts.clone());
60+
if cache_enabled && let Some(ts) = &ts_opt {
61+
self.ts_cache.push(tsk.clone(), ts.clone());
6262
metrics::LRU_CACHE_MISS
6363
.get_or_create(&metrics::values::TIPSET)
6464
.inc();

0 commit comments

Comments
 (0)