Skip to content

Commit 24ab830

Browse files
authored
chore: limit Vec preallocation to follow serde convention (#6616)
1 parent 63a6089 commit 24ab830

File tree

3 files changed

+26
-8
lines changed

3 files changed

+26
-8
lines changed

src/chain/store/chain_store.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -537,12 +537,11 @@ where
537537
{
538538
let amt = Amt::<Cid, _>::load(root, db)?;
539539

540-
let mut cids = Vec::new();
541-
for i in 0..amt.count() {
542-
if let Some(c) = amt.get(i)? {
543-
cids.push(*c);
544-
}
545-
}
540+
let mut cids = Vec::with_capacity(amt.count() as usize);
541+
amt.for_each_cacheless(|_, c| {
542+
cids.push(*c);
543+
Ok(())
544+
})?;
546545

547546
Ok(cids)
548547
}

src/utils/encoding/cid_de_cbor.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ impl<'de> DeserializeSeed<'de> for FilterCids<'_> {
6363
where
6464
V: de::MapAccess<'de>,
6565
{
66-
self.0.reserve(visitor.size_hint().unwrap_or(0));
66+
let capacity = super::size_hint_cautious_cid(visitor.size_hint().unwrap_or(0));
67+
self.0.reserve(capacity);
6768
// This is where recursion happens, we unravel each [`Ipld`] till we reach all
6869
// the nodes.
6970
while visitor
@@ -83,7 +84,8 @@ impl<'de> DeserializeSeed<'de> for FilterCids<'_> {
8384
where
8485
A: SeqAccess<'de>,
8586
{
86-
self.0.reserve(seq.size_hint().unwrap_or(0));
87+
let capacity = super::size_hint_cautious_cid(seq.size_hint().unwrap_or(0));
88+
self.0.reserve(capacity);
8789
// This is where recursion happens, we unravel each [`Ipld`] till we reach all
8890
// the nodes.
8991
while seq.next_element_seed(FilterCids(self.0))?.is_some() {

src/utils/encoding/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ use serde::{Deserializer, Serializer, de, ser};
99

1010
mod fallback_de_ipld_dagcbor;
1111

12+
/// Limit the the number of bytes that are used for pre-allocating `Vec<Cid>`s. This follows what `serde` is
13+
/// doing internally with `serde::private::size_hint::cautious()`.
14+
/// The limit is set to 1 MiB, which is a reasonable upper bound for most use cases.
15+
fn size_hint_cautious_cid(size_hint: usize) -> usize {
16+
const MAX_PREALLOC_BYTES: usize = 1024 * 1024;
17+
size_hint.min(MAX_PREALLOC_BYTES / std::mem::size_of::<cid::Cid>())
18+
}
19+
1220
/// This method will attempt to de-serialize given bytes using the regular
1321
/// `serde_ipld_dagcbor::from_slice`. Due to a historical issue in Lotus (see more in
1422
/// [FIP-0027](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0027.md), we must still
@@ -258,4 +266,13 @@ mod tests {
258266
matches!(from_slice_with_fallback::<Ipld>(&corrupted).unwrap(), Ipld::Bytes(bytes) if bytes == [0x63, 0x74, 0x68, 0x75, 0x6c, 0xa0, 0xa1])
259267
)
260268
}
269+
270+
#[test]
271+
fn size_hint_cautious_test() {
272+
assert_eq!(size_hint_cautious_cid(0), 0);
273+
assert_eq!(
274+
size_hint_cautious_cid(1024 * 1024),
275+
1024 * 1024 / std::mem::size_of::<cid::Cid>()
276+
);
277+
}
261278
}

0 commit comments

Comments
 (0)