Skip to content

Conversation

@hanabi1224
Copy link
Contributor

@hanabi1224 hanabi1224 commented Aug 8, 2025

Summary of changes

Changes introduced in this pull request:

  • track TipsetStateCache size with prometheus metrics by replacing LruCache with SizeTrackingLruCache
  • implement GetSize for related types
  • tests

metrics on mainnet

# HELP tipset_state_cache_state_events_5_size_bytes Size of LruCache tipset_state_cache_state_events_5 in bytes
# TYPE tipset_state_cache_state_events_5_size_bytes gauge
# UNIT tipset_state_cache_state_events_5_size_bytes bytes
tipset_state_cache_state_events_5_size_bytes 6263820
# HELP tipset_state_cache_state_events_5_len Length of LruCache tipset_state_cache_state_events_5
# TYPE tipset_state_cache_state_events_5_len gauge
tipset_state_cache_state_events_5_len 27
# HELP tipset_state_cache_state_events_5_cap Capacity of LruCache tipset_state_cache_state_events_5
# TYPE tipset_state_cache_state_events_5_cap gauge
tipset_state_cache_state_events_5_cap 4096
# HELP tipset_state_cache_vec<receipt>_6_size_bytes Size of LruCache tipset_state_cache_vec<receipt>_6 in bytes
# TYPE tipset_state_cache_vec<receipt>_6_size_bytes gauge
# UNIT tipset_state_cache_vec<receipt>_6_size_bytes bytes
tipset_state_cache_vec<receipt>_6_size_bytes 264432
# HELP tipset_state_cache_vec<receipt>_6_len Length of LruCache tipset_state_cache_vec<receipt>_6
# TYPE tipset_state_cache_vec<receipt>_6_len gauge
tipset_state_cache_vec<receipt>_6_len 27
# HELP tipset_state_cache_vec<receipt>_6_cap Capacity of LruCache tipset_state_cache_vec<receipt>_6
# TYPE tipset_state_cache_vec<receipt>_6_cap gauge
tipset_state_cache_vec<receipt>_6_cap 4096
# HELP tipset_state_cache_state_output_value_7_size_bytes Size of LruCache tipset_state_cache_state_output_value_7 in bytes
# TYPE tipset_state_cache_state_output_value_7_size_bytes gauge
# UNIT tipset_state_cache_state_output_value_7_size_bytes bytes
tipset_state_cache_state_output_value_7_size_bytes 695040
# HELP tipset_state_cache_state_output_value_7_len Length of LruCache tipset_state_cache_state_output_value_7
# TYPE tipset_state_cache_state_output_value_7_len gauge
tipset_state_cache_state_output_value_7_len 1024
# HELP tipset_state_cache_state_output_value_7_cap Capacity of LruCache tipset_state_cache_state_output_value_7
# TYPE tipset_state_cache_state_output_value_7_cap gauge
tipset_state_cache_state_output_value_7_cap 1024

Reference issue to close (if applicable)

Closes

Other information and links

Change checklist

  • I have performed a self-review of my own code,
  • I have made corresponding changes to the documentation. All new code adheres to the team's documentation standards,
  • I have added tests that prove my fix is effective or that my feature works (if possible),
  • I have made sure the CHANGELOG is up-to-date. All user-facing changes should be reflected in this document.

Summary by CodeRabbit

  • New Features

    • Added heap size calculation support for various types, enabling more accurate memory usage tracking.
    • Introduced a utility to obtain simplified type names for easier identification.
    • Enhanced cache implementation with size tracking and metrics integration.
  • Bug Fixes

    • Improved memory efficiency in key conversions by reducing unnecessary heap allocation.
  • Refactor

    • Replaced the underlying LRU cache with a size-tracking variant for better performance and observability.
    • Renamed internal traits and updated public exports for clarity and consistency.
    • Moved state manager tests to a dedicated test module for better organization.
  • Tests

    • Added comprehensive tests for state lookup, cache updates, and memory size calculations.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 8, 2025

Walkthrough

This set of changes refactors and enhances cache management and memory size tracking across several modules. It replaces the LRU cache implementation in the state manager with a size-tracking variant using a new LruValueConstraints trait, updates related trait and struct derivations, and introduces new helper utilities for type name simplification and heap size calculation. Inline tests are moved to a dedicated file, and new tests are added for state management and utility functions.

Changes

Cohort / File(s) Change Summary
Dependency Addition
Cargo.toml
Added convert_case v0.8 to dependencies.
TipsetKey Enhancements
src/blocks/tipset.rs
Grouped imports, derived GetSize for TipsetKey, and optimized From<NonEmpty<Cid>> by shrinking capacity before conversion.
CID Collections Updates
src/cid_collections/mod.rs, src/cid_collections/small_cid_vec.rs
Added/derived GetSize for several structs/enums, changed SmallCid::Indirect to hold Uncompactable directly, and implemented heap size calculation for SmallCidNonEmptyVec.
Receipt/Event Size Tracking
src/shim/executor.rs
Implemented GetSize trait for Receipt and StampedEvent enums to track heap size.
State Manager Cache Refactor
src/state_manager/cache.rs, src/utils/cache/lru.rs, src/utils/cache/mod.rs
Replaced LruCache with SizeTrackingLruCache requiring LruValueConstraints, updated all related API uses, renamed trait, and updated exports.
State Manager Structs and Test Relocation
src/state_manager/mod.rs, src/state_manager/tests.rs
Moved inline tests to a new file, derived Debug and GetSize for StateEvents and StateOutputValue, added size calculation annotations, and introduced comprehensive new tests.
Heap Size Utility Enhancements
src/utils/get_size/mod.rs
Publicly re-exported GetSize, added macros and helpers for heap size calculation of vector-like collections, and added tests.
Miscellaneous Utilities
src/utils/misc/mod.rs, src/utils/misc/type.rs
Added and re-exported new r#type module with a utility function for generating short type names, including tests.

Sequence Diagram(s)

sequenceDiagram
    participant StateManager
    participant TipsetStateCache
    participant SizeTrackingLruCache
    participant MetricsRegistry

    StateManager->>TipsetStateCache: lookup_or_insert(key, value)
    TipsetStateCache->>SizeTrackingLruCache: get_cloned(key)
    alt Not in cache
        TipsetStateCache->>SizeTrackingLruCache: push(key, value)
    end
    SizeTrackingLruCache->>MetricsRegistry: record_size(cache_name)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

  • ChainSafe/forest#5841: Implements and introduces SizeTrackingLruCache and associated traits, which are directly refactored and adopted in this PR.
  • ChainSafe/forest#5848: Enhances LRU cache metrics and usage of SizeTrackingLruCache in various code parts, closely related to cache refactoring here.

Suggested labels

RPC

Suggested reviewers

  • LesnyRumcajs
  • akaladarshi

Note

🔌 MCP (Model Context Protocol) integration is now available in Early Access!

Pro users can now connect to remote MCP servers under the Integrations page to get reviews and chat conversations that understand additional development context.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eaa9828 and ddc6094.

📒 Files selected for processing (4)
  • src/blocks/tipset.rs (2 hunks)
  • src/cid_collections/mod.rs (3 hunks)
  • src/shim/executor.rs (3 hunks)
  • src/state_manager/mod.rs (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/cid_collections/mod.rs
  • src/blocks/tipset.rs
  • src/shim/executor.rs
  • src/state_manager/mod.rs
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch hm/tipset-state-cache-metrics

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@hanabi1224 hanabi1224 marked this pull request as ready for review August 8, 2025 02:56
@hanabi1224 hanabi1224 requested a review from a team as a code owner August 8, 2025 02:56
@hanabi1224 hanabi1224 requested review from LesnyRumcajs and sudo-shashank and removed request for a team August 8, 2025 02:56
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/state_manager/tests.rs (1)

447-452: Add newline at end of file.

 #[test]
 fn test_state_output_get_size() {
     let s = StateOutputValue::default();
     assert_eq!(s.get_size(), std::mem::size_of_val(&s));
 }
+
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 163eeb4 and 70dba69.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (13)
  • Cargo.toml (1 hunks)
  • src/blocks/tipset.rs (2 hunks)
  • src/cid_collections/mod.rs (3 hunks)
  • src/cid_collections/small_cid_vec.rs (5 hunks)
  • src/shim/executor.rs (3 hunks)
  • src/state_manager/cache.rs (5 hunks)
  • src/state_manager/mod.rs (4 hunks)
  • src/state_manager/tests.rs (1 hunks)
  • src/utils/cache/lru.rs (3 hunks)
  • src/utils/cache/mod.rs (1 hunks)
  • src/utils/get_size/mod.rs (2 hunks)
  • src/utils/misc/mod.rs (1 hunks)
  • src/utils/misc/type.rs (1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: hanabi1224
PR: ChainSafe/forest#5841
File: src/utils/get_size/mod.rs:10-10
Timestamp: 2025-07-17T15:21:40.753Z
Learning: The get_size2 crate's GetSize trait provides default implementations: get_stack_size() uses std::mem::size_of, get_heap_size() returns 0, and get_size() returns their sum. An empty impl like `impl GetSize for MyType {}` is valid and uses these defaults, making it suitable for simple wrapper types that don't allocate heap memory.
📚 Learning: 2025-07-17T15:21:40.753Z
Learnt from: hanabi1224
PR: ChainSafe/forest#5841
File: src/utils/get_size/mod.rs:10-10
Timestamp: 2025-07-17T15:21:40.753Z
Learning: The get_size2 crate's GetSize trait provides default implementations: get_stack_size() uses std::mem::size_of, get_heap_size() returns 0, and get_size() returns their sum. An empty impl like `impl GetSize for MyType {}` is valid and uses these defaults, making it suitable for simple wrapper types that don't allocate heap memory.

Applied to files:

  • src/utils/cache/lru.rs
  • src/shim/executor.rs
  • src/blocks/tipset.rs
  • src/cid_collections/small_cid_vec.rs
  • src/utils/get_size/mod.rs
  • src/cid_collections/mod.rs
  • src/state_manager/mod.rs
📚 Learning: 2025-08-06T15:42:43.520Z
Learnt from: LesnyRumcajs
PR: ChainSafe/forest#5907
File: Cargo.toml:25-36
Timestamp: 2025-08-06T15:42:43.520Z
Learning: The fvm_ipld_amt crate version 0.7.5 is required for the Forest project, but it's not yet published to crates.io, which is why the Git patch pointing to the ref-fvm repository is still necessary.

Applied to files:

  • src/shim/executor.rs
📚 Learning: 2025-08-04T13:36:22.993Z
Learnt from: hanabi1224
PR: ChainSafe/forest#5835
File: src/chain/tests.rs:58-76
Timestamp: 2025-08-04T13:36:22.993Z
Learning: In the Forest codebase, `Vec<u8>` can be used as an `AsyncWrite` implementation in test contexts. The user confirmed that tests using `&mut Vec<u8>` with `export` and `export_v2` functions compile and pass both locally and on CI.

Applied to files:

  • src/utils/get_size/mod.rs
  • src/cid_collections/mod.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Build forest binaries on Linux AMD64
  • GitHub Check: tests
  • GitHub Check: tests-release
  • GitHub Check: cargo-publish-dry-run
  • GitHub Check: Build Ubuntu
  • GitHub Check: Build MacOS
  • GitHub Check: All lint checks
  • GitHub Check: Analyze (rust)
  • GitHub Check: Analyze (go)
🔇 Additional comments (28)
Cargo.toml (1)

54-54: convert_case dependency is up-to-date and secure

  • Cargo.toml (line 54): convert_case = "0.8" corresponds to the latest stable version (0.8.0) as of August 2025.
  • No public security advisories or vulnerabilities have been reported for this crate.

No further action needed. For production assurance, periodically review the RustSec Advisory Database or crates.io for any future advisories.

src/utils/misc/mod.rs (1)

11-12: LGTM - Clean module addition

The addition of the r#type module with glob re-export is well-structured. Using the raw identifier r#type is the correct approach since type is a reserved keyword in Rust.

src/utils/cache/mod.rs (1)

5-5: LGTM - Appropriate API expansion

Adding LruValueConstraints to the public exports is consistent with the trait being used as a generic bound in other modules, particularly in src/state_manager/cache.rs.

src/utils/cache/lru.rs (2)

38-40: LGTM - Better trait naming

The rename from ValueConstraints to LruValueConstraints improves clarity and specificity. The trait definition and blanket implementation are correctly updated.


46-46: LGTM - Consistent trait reference updates

All references to the trait in generic bounds have been consistently updated to use the new LruValueConstraints name.

Also applies to: 56-56, 169-169

src/cid_collections/mod.rs (4)

41-41: LGTM - Clean imports for GetSize integration

The import changes support the GetSize trait integration. The glob import super::* is reasonable given the expanded usage, and the get_size2::GetSize import is correctly placed.

Also applies to: 44-44


48-48: LGTM - Appropriate GetSize trait derivations

The GetSize trait derivations for both CidV1DagCborBlake2b256 and Uncompactable are correctly implemented. These structs are suitable for the derive macro as they are simple wrapper types.

Also applies to: 103-103


106-107: Good use of get_size ignore attribute

The #[get_size(ignore)] attribute on the inner: Cid field is appropriate since Cid likely doesn't implement GetSize. This ensures the size calculation focuses only on the wrapper overhead.


159-165: LGTM - Comprehensive test for GetSize implementation

The test verifies that Uncompactable::get_size() returns the size of its inner Cid field, which is the expected behavior given the #[get_size(ignore)] attribute. The test correctly uses std::mem::size_of_val for comparison.

src/shim/executor.rs (3)

8-8: LGTM!

The import of GetSize trait and helper function is necessary for the size tracking implementations added below.


137-145: LGTM!

The GetSize implementation for Receipt correctly calculates heap size by focusing on the return_data.bytes() across all variants, which represents the main heap-allocated content in receipts.


347-358: LGTM!

The GetSize implementation for StampedEvent correctly calculates heap size by summing the heap sizes of key and value fields in each entry using the helper function. The implementation properly handles both V3 and V4 variants.

src/blocks/tipset.rs (3)

9-15: LGTM!

Good import organization and the GetSize import is necessary for the trait derivation added to TipsetKey.

Also applies to: 21-21


33-33: LGTM!

Adding GetSize derivation to TipsetKey is correct and supports the cache size tracking functionality. The underlying SmallCidNonEmptyVec also implements GetSize, ensuring proper size calculation.


104-107: LGTM!

Excellent memory optimization! Calling shrink_to_fit() before conversion reduces heap usage for cached TipsetKey instances. The rationale is well-documented and the approach is sound since TipsetKey is immutable.

src/utils/misc/type.rs (2)

6-10: LGTM!

The short_type_name function implementation is well-designed with efficient regex pattern matching and appropriate use of Cow<'static, str> for memory efficiency. The regex correctly strips module paths while preserving type structure.


18-31: LGTM!

Excellent test coverage! The tests validate the function works correctly for simple types, nested generics, and lifetime parameters. The expected outputs confirm the regex properly strips module paths while preserving essential type information.

src/cid_collections/small_cid_vec.rs (4)

5-5: LGTM!

The GetSize implementation for SmallCidNonEmptyVec correctly uses the helper function to calculate heap size of the underlying NonEmpty<SmallCid> collection.

Also applies to: 25-29


82-82: LGTM!

Adding GetSize derivation to SmallCid enum is correct and will properly handle heap size calculation for both Inline and Indirect variants.


85-85: LGTM!

Excellent optimization! Removing the Box indirection from the Indirect variant reduces unnecessary heap allocation while maintaining the same external behavior.


96-96: LGTM!

The From implementation updates correctly reflect the removal of Box indirection. The conversions maintain the same external behavior while working with the optimized internal representation.

Also applies to: 105-105

src/state_manager/mod.rs (2)

98-104: Verify the appropriateness of size calculation helpers for StateEvents fields.

The vec_heap_size_helper is used for events field which contains nested vectors. This should correctly calculate heap size for Vec<Vec<StampedEvent>> assuming StampedEvent implements GetSize.

The vec_with_stack_only_item_heap_size_helper is used for roots field of type Vec<Option<Cid>>. Since Option<Cid> is a stack-only type (Cid contains no heap allocations), this choice is appropriate.


114-120: Ignore the #[get_size(ignore)] on Cid fields

The Cid type itself doesn’t implement GetSize, so omitting these fields is required for the derive to compile. If you do want their fixed stack size included, you’ll need to add a GetSize impl (or wrap Cid in a newtype with a default impl) rather than dropping the ignore here.

• Location: src/state_manager/mod.rs lines 114–120
• Rationale: no impl GetSize for Cid exists, so removing ignore will cause a compile error

Likely an incorrect or invalid review comment.

src/state_manager/tests.rs (1)

21-451: Well-structured and comprehensive test coverage!

The tests thoroughly cover:

  • State lookup scenarios with various edge cases
  • Cache update behavior for both receipts and events
  • Size calculation for StateOutputValue

The test utilities and setup helpers are well-organized and make the tests readable.

src/utils/get_size/mod.rs (1)

68-76: Good test coverage for heap size calculation.

The test correctly verifies that the heap size calculation accounts for the full capacity of the vector, not just the length.

src/state_manager/cache.rs (3)

45-51: Well-implemented cache naming for metrics.

The cache_name() method cleverly generates a descriptive snake_case name from the type parameter, which will produce meaningful metric names like tipset_state_cache_state_output_value.


17-42: Excellent integration of size-tracking cache with metrics.

The replacement of LruCache with SizeTrackingLruCache and the requirement for values to implement LruValueConstraints enables proper memory tracking. The automatic metrics registration with type-based naming is a clean solution.


335-537: Comprehensive concurrent access test coverage!

The tests thoroughly validate:

  • Basic cache functionality
  • Concurrent access to the same key (ensuring single computation)
  • Concurrent access to different keys
  • Enabled vs disabled cache behavior

These tests provide confidence in the thread-safety and correctness of the cache implementation.

@hanabi1224 hanabi1224 force-pushed the hm/tipset-state-cache-metrics branch from 4753e1a to eaa9828 Compare August 8, 2025 03:26
impl From<NonEmpty<Cid>> for TipsetKey {
fn from(value: NonEmpty<Cid>) -> Self {
fn from(mut value: NonEmpty<Cid>) -> Self {
// When `value.capacity() > value.len()`, it takes more heap memory.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like it. 🧠

#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Ord, PartialOrd, GetSize)]
#[repr(transparent)]
pub struct Uncompactable {
#[get_size(ignore)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignore means heap size = 0, not intuitive naming

@LesnyRumcajs LesnyRumcajs added this pull request to the merge queue Aug 11, 2025
Merged via the queue into main with commit ba8fc4b Aug 11, 2025
43 checks passed
@LesnyRumcajs LesnyRumcajs deleted the hm/tipset-state-cache-metrics branch August 11, 2025 07:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants