Skip to content

perf: add small root-node MRU cache for MARF storage connections#6944

Open
cylewitruk-stacks wants to merge 8 commits intostacks-network:developfrom
cylewitruk-stacks:perf/marf-root-node-mru-cache
Open

perf: add small root-node MRU cache for MARF storage connections#6944
cylewitruk-stacks wants to merge 8 commits intostacks-network:developfrom
cylewitruk-stacks:perf/marf-root-node-mru-cache

Conversation

@cylewitruk-stacks
Copy link

@cylewitruk-stacks cylewitruk-stacks commented Feb 27, 2026

Description

Adds a small 4-entry MRU cache for root trie nodes in TrieStorageConnection (via TrieStorageTransientData), minimizing disk lookups as all gets start at the root node.

Excludes unconfirmed blocks since their blobs are updated in-place (a cached entry would go stale on re-flush).

The cache is cloned when forking read-only connections, and cleared at all unconfirmed trie invalidation points.

Applicable issues

  • Not related to any specific issue, falls within the 100x chain optimization targets.

Additional info (benefits, drawbacks, caveats)

  • Only active under TrieCache::Noop; other cache modes fall-through unchanged.
  • New tests to verify the caching paths and helpers to support those tests.

Benchmark results

Using the benchmarks in #6932 -- noop cache mode shows a ~25-33% improvement in get timings, ~17% reduction in number of allocations and ~25% reduction in bytes allocated (based on synthetic data).

[marf-bench] Comparison summary
values: base:b61a7660e550d67a9fce3ea9e1050bd4deb7f705 / target:8d0b9e062d06770f91f86a2bb912887bf351d703 / %delta
benchmark  name                                total(ms) b/t       Δ  alloc_count b/t       Δ          alloc_bytes b/t       Δ
------------------------------------------------------------------------------------------------------------------------------
read       node256/depth=128/variant=get   1079.516/1104.864   +2.3%  4400006/4400006   +0.0%    5652817794/5652817794   +0.0%
read       node256/depth=2047/variant=get  1889.555/1913.063   +1.2%  4800006/4800006   +0.0%    7985617794/7985617794   +0.0%
read       node256/depth=32/variant=get    1899.678/1908.497   +0.5%  4800014/4800014   +0.0%    7985635716/7985635716   +0.0%
read       node256/depth=768/variant=get   1875.432/1906.347   +1.6%  4800006/4800006   +0.0%    7985617794/7985617794   +0.0%
read       noop/depth=128/variant=get      2773.425/2086.292  -24.8%  6800000/5600000  -17.6%   12770400000/9211600000  -27.9%
read       noop/depth=2047/variant=get     3614.398/3041.673  -15.8%  7200000/6000000  -16.7%  15103200000/11544400000  -23.6%
read       noop/depth=32/variant=get       3640.954/2996.408  -17.7%  7200002/6000008  -16.7%  15103200128/11544417922  -23.6%
read       noop/depth=768/variant=get      3624.238/3028.314  -16.4%  7200000/6000000  -16.7%  15103200000/11544400000  -23.6%
------------------------------------------------------------------------------------------------------------------------------

[marf-bench] Repeated comparison stats
baseline: base:b61a7660e550d67a9fce3ea9e1050bd4deb7f705
comparison: target:8d0b9e062d06770f91f86a2bb912887bf351d703
values: median/min/max %delta across 5 repeats
high-confidence rows (low/no jitter):
benchmark  name                             total Δ med   total Δ min   total Δ max   count Δ med   bytes Δ med  repeats
------------------------------------------------------------------------------------------------------------------------
read       node256/depth=128/variant=get          -0.6%        -12.5%         +9.6%         +0.0%         +0.0%        5
read       node256/depth=2047/variant=get         -0.9%        -14.0%        +10.9%         +0.0%         +0.0%        5
read       node256/depth=32/variant=get           -1.1%        -11.4%        +10.6%         +0.0%         +0.0%        5
read       node256/depth=768/variant=get          +1.6%        -11.7%        +12.3%         +0.0%         +0.0%        5
read       noop/depth=128/variant=get            -33.1%        -44.4%         -9.4%        -17.6%        -27.9%        5
read       noop/depth=2047/variant=get           -25.3%        -41.5%         -5.2%        -16.7%        -23.6%        5
read       noop/depth=32/variant=get             -25.7%        -38.6%         -5.8%        -16.7%        -23.6%        5
read       noop/depth=768/variant=get            -26.0%        -39.4%         -4.2%        -16.7%        -23.6%        5
------------------------------------------------------------------------------------------------------------------------

low-confidence rows (high-jitter):
(none)

[marf-bench] Repeat confidence summary
baseline: base:b61a7660e550d67a9fce3ea9e1050bd4deb7f705
comparison: target:8d0b9e062d06770f91f86a2bb912887bf351d703
values: total_ms stability across 5 repeats
rows: total=8 stable=8 high-jitter=0  (high-jitter means min<0<max and spread>=30.0%)
high-jitter rows: none

Checklist

  • Test coverage for new or modified code paths
  • Changelog is updated

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a small (4-entry) root-node MRU cache to TrieStorageConnection (via TrieStorageTransientData) to reduce repeated root node disk reads in TrieCache::Noop mode.

Changes:

  • Add an array-backed 4-entry MRU cache for committed-block root trie nodes (only active under TrieCache::Noop).
  • Clear/clone root cache at connection fork/reopen and at unconfirmed invalidation/flush points to avoid stale reads.
  • New tests and related helpers for confirmed/unconfirmed scenarios and MRU behavior.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
stackslib/src/chainstate/stacks/index/storage.rs Adds root-node MRU cache field, wiring, and cache-hit/miss fast path for root reads in TrieCache::Noop.
stackslib/src/chainstate/stacks/index/cache.rs Introduces MruCache (fixed-capacity array-backed MRU/LRU-eviction structure).
stackslib/src/chainstate/stacks/index/test/storage.rs Adds tests for root cache correctness, eviction, unconfirmed skipping, and reopen cloning.
stackslib/src/chainstate/stacks/index/test/mod.rs Adds shared helpers for temp MARF paths, minimal chains, and unconfirmed transactional inserts.
stackslib/src/chainstate/stacks/index/test/marf.rs Adds regression test for repeated unconfirmed re-flushes preserving latest state.
stackslib/src/chainstate/stacks/index/test/cache.rs Adds unit tests covering MruCache promotion/eviction/clear/capacity edge cases.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@codecov
Copy link

codecov bot commented Feb 27, 2026

Codecov Report

❌ Patch coverage is 21.77419% with 291 lines in your changes missing coverage. Please review.
✅ Project coverage is 56.52%. Comparing base (58545bc) to head (5e927e1).

Files with missing lines Patch % Lines
...ckslib/src/chainstate/stacks/index/test/storage.rs 0.00% 115 Missing ⚠️
stackslib/src/chainstate/stacks/index/test/mod.rs 0.00% 72 Missing ⚠️
...tackslib/src/chainstate/stacks/index/test/cache.rs 7.84% 47 Missing ⚠️
stackslib/src/chainstate/stacks/index/test/marf.rs 0.00% 26 Missing ⚠️
stackslib/src/chainstate/stacks/index/cache.rs 63.46% 19 Missing ⚠️
stackslib/src/chainstate/stacks/index/storage.rs 78.57% 12 Missing ⚠️

❗ There is a different number of reports uploaded between BASE (58545bc) and HEAD (5e927e1). Click for more details.

HEAD has 15 uploads less than BASE
Flag BASE (58545bc) HEAD (5e927e1)
132 117
Additional details and impacted files
@@             Coverage Diff              @@
##           develop    #6944       +/-   ##
============================================
- Coverage    77.73%   56.52%   -21.21%     
============================================
  Files          412      412               
  Lines       218667   219032      +365     
  Branches       338      338               
============================================
- Hits        169981   123813    -46168     
- Misses       48686    95219    +46533     
Files with missing lines Coverage Δ
stackslib/src/chainstate/stacks/index/storage.rs 80.41% <78.57%> (-0.23%) ⬇️
stackslib/src/chainstate/stacks/index/cache.rs 76.19% <63.46%> (-9.85%) ⬇️
stackslib/src/chainstate/stacks/index/test/marf.rs 13.04% <0.00%> (-38.16%) ⬇️
...tackslib/src/chainstate/stacks/index/test/cache.rs 55.27% <7.84%> (-42.00%) ⬇️
stackslib/src/chainstate/stacks/index/test/mod.rs 73.84% <0.00%> (-21.81%) ⬇️
...ckslib/src/chainstate/stacks/index/test/storage.rs 53.49% <0.00%> (-38.10%) ⬇️

... and 311 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 58545bc...5e927e1. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cylewitruk-stacks cylewitruk-stacks changed the title perf: tiny MARF root-node MRU cache perf: add small root-node MRU cache for MARF storage connections Feb 28, 2026
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.

2 participants