implement collapse manager - #7373
Conversation
…aves # Conflicts: # common/interface.go # integrationTests/state/stateTrie/stateTrie_test.go # state/accountsDB_test.go # state/storagePruningManager/storagePruningManager_test.go # testscommon/components/components.go # trie/branchNode_test.go # trie/extensionNode_test.go # trie/interface.go # trie/node.go # trie/patriciaMerkleTrie.go
There was a problem hiding this comment.
Pull request overview
This PR introduces a trie “collapse manager” abstraction and wires it into Patricia Merkle Trie creation/commit paths, aiming to control in-memory trie growth by collapsing nodes (primarily leaves) based on memory usage and recent access patterns.
Changes:
- Replaced
trie.NewTrie(..., maxSizeInMemory uint64)withtrie.NewTrie(..., collapseManager common.TrieCollapseManager)across the codebase. - Added
trie/collapseManagerpackage with enabled (NewCollapseManager) and disabled (NewDisabledCollapseManager) implementations. - Updated trie commit/collapse behavior and extended node interface (
shouldCollapseChild) + adjusted tests accordingly.
Reviewed changes
Copilot reviewed 40 out of 40 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| update/genesis/import.go | Updates trie construction to pass a collapse manager (currently disabled) during import. |
| update/factory/dataTrieFactory.go | Updates data trie factory to pass a collapse manager (currently disabled). |
| trie/sync_test.go | Adjusts tests for commitDirty signature change. |
| trie/patriciaMerkleTrie_test.go | Updates tests for new collapse behavior and adds a collapse test. |
| trie/patriciaMerkleTrie.go | Integrates collapse manager into trie size tracking and commit flow. |
| trie/node_test.go | Updates tests for commitDirty signature change; removes isLeafNode test. |
| trie/leafNode_test.go | Updates tests for commitDirty signature change; adds shouldCollapseChild test. |
| trie/leafNode.go | Updates commitDirty signature and adds shouldCollapseChild. |
| trie/interface.go | Adds shouldCollapseChild and updates commitDirty signature in the node interface. |
| trie/factory/trieCreator.go | Creates a real collapse manager from MaxSizeInMemory and passes it to NewTrie. |
| trie/extensionNode_test.go | Updates tests for commitDirty signature change; adds shouldCollapseChild tests. |
| trie/extensionNode.go | Updates commitDirty signature and adds shouldCollapseChild. |
| trie/export_test.go | Adds a test-only helper to count collapsed nodes. |
| trie/errors.go | Adds ErrNilCollapseManager. |
| trie/doubleListSync_test.go | Updates trie creation to pass a collapse manager (disabled). |
| trie/collapseManager/disabledCollapseManager_test.go | Adds tests for the disabled collapse manager implementation. |
| trie/collapseManager/disabledCollapseManager.go | Implements a no-op collapse manager. |
| trie/collapseManager/collapseManager_test.go | Adds tests for the enabled collapse manager implementation. |
| trie/collapseManager/collapseManager.go | Implements enabled collapse manager logic (LRU-like). |
| trie/branchNode_test.go | Updates tests for commitDirty signature change; adds shouldCollapseChild tests. |
| trie/branchNode.go | Updates commitDirty signature and removes unconditional leaf collapse; adds shouldCollapseChild. |
| testscommon/state/testTrie.go | Updates helper to create tries with a collapse manager (disabled). |
| testscommon/integrationtests/factory.go | Updates trie creation to pass a collapse manager (disabled). |
| testscommon/components/components.go | Updates component wiring to pass a collapse manager (disabled). |
| state/syncer/userAccountsSyncer_test.go | Updates test helpers and trie creation to pass a collapse manager (disabled). |
| state/syncer/userAccountSyncer_test.go | Updates test trie creation to pass a collapse manager (disabled). |
| state/syncer/baseAccountsSyncer.go | Updates trie creation to pass a collapse manager (disabled) in deprecated path. |
| state/storagePruningManager/storagePruningManager_test.go | Updates test trie creation to pass a collapse manager (disabled). |
| state/accountsDB_test.go | Updates test trie creation to pass a collapse manager (disabled). |
| state/accountsDB.go | Clarifies commit step comment for data tries. |
| integrationTests/vm/staking/componentsHolderCreator.go | Updates trie creation to pass a collapse manager (disabled). |
| integrationTests/testInitializer.go | Updates trie creation to pass a collapse manager (disabled). |
| integrationTests/state/stateTrieClose/stateTrieClose_test.go | Updates test trie creation to pass a collapse manager (disabled). |
| integrationTests/state/stateTrie/stateTrie_test.go | Updates test trie creation to pass a collapse manager (disabled). |
| integrationTests/longTests/storage/storage_test.go | Updates test trie creation to pass a collapse manager (disabled). |
| integrationTests/benchmarks/loadFromTrie_test.go | Updates benchmark trie creation to pass a collapse manager (disabled). |
| genesis/process/memoryComponents.go | Updates genesis in-memory trie creation to pass a collapse manager (disabled). |
| factory/processing/blockProcessorCreator_test.go | Updates test trie creation to pass a collapse manager (disabled). |
| epochStart/metachain/systemSCs_test.go | Updates test trie creation to pass a collapse manager (disabled). |
| common/interface.go | Introduces common.TrieCollapseManager interface. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 40 out of 40 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…' into collapse-main-trie-leaves # Conflicts: # genesis/process/memoryComponents.go # state/accountsDB_test.go
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## feat/collapse-trie-based-on-size #7373 +/- ##
====================================================================
- Coverage 77.55% 77.54% -0.01%
====================================================================
Files 884 885 +1
Lines 123834 123844 +10
====================================================================
- Hits 96039 96035 -4
- Misses 21442 21450 +8
- Partials 6353 6359 +6 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
| // TODO calibrate these values | ||
| numLeavesToCollapseSingleRun = 100 | ||
| minNumLeavesToCollapseTrie = 1000 | ||
| minSizeInMemory = 1048576 // 1 MB |
There was a problem hiding this comment.
maybe these values should be moved in the config.toml file ?
There was a problem hiding this comment.
Moved only numLeavesToCollapseSingleRun in config, the other const are only checks that the existing config vals are ok.
| for i := range current.children { | ||
| if current.children[i] != nil { | ||
| nextNodes = append(nextNodes, current.children[i]) | ||
| } | ||
| if current.children[i] == nil && len(current.EncodedChildren[i]) != 0 { | ||
| count++ | ||
| } | ||
| } |
There was a problem hiding this comment.
| for i := range current.children { | |
| if current.children[i] != nil { | |
| nextNodes = append(nextNodes, current.children[i]) | |
| } | |
| if current.children[i] == nil && len(current.EncodedChildren[i]) != 0 { | |
| count++ | |
| } | |
| } | |
| for i := range current.children { | |
| if current.children[i] != nil { | |
| nextNodes = append(nextNodes, current.children[i]) | |
| } else if len(current.EncodedChildren[i]) != 0 { | |
| count++ | |
| } | |
| } |
| if cm.sizeInMemory+size < 0 { | ||
| log.Warn("trie size in memory is negative after adding size, resetting to 0", "size", size, "currentSize", cm.sizeInMemory) | ||
| cm.sizeInMemory = 0 | ||
| return | ||
| } | ||
| cm.sizeInMemory += size |
There was a problem hiding this comment.
do we need mutex protection for sizeInMemory ?
There was a problem hiding this comment.
Not right now. This component is used only by the trie, and is protected by the trie mutex.
| // GetCollapsibleLeaves returns a list of keys that can be collapsed to free memory | ||
| func (cm *collapseManager) GetCollapsibleLeaves() ([][]byte, error) { | ||
| if uint64(cm.sizeInMemory) < cm.maxSizeInMem { | ||
| return nil, nil |
There was a problem hiding this comment.
| return nil, nil | |
| return make([][]byte, 0), nil |
*optional: to avoid nil, nil confusion
| func (cm *collapseManager) ShouldCollapseTrie() bool { | ||
| // we collapse only if we are over the memory limit and there are not enough accessed keys to | ||
| // free memory by collapsing only leaves | ||
| if uint64(cm.sizeInMemory) > cm.maxSizeInMem && len(cm.accessedKeys) < minNumLeavesToCollapseTrie { |
There was a problem hiding this comment.
why second condition? maybe rename const minNumLeavesToCollapseTrie?
There was a problem hiding this comment.
- add a unit test case also for this?
There was a problem hiding this comment.
There is a unit test for this: TestCollapseManager_ShouldCollapseTrie.
The second condition is ment for when the trie size is composed of mostly intermediary nodes and there are only a few leaves. Only leaves are collapsed so if we have only a few leaves left to collapse, the collapse will be triggered every commit. If we reach this state of a trie, we should recreate the trie. This will also collapse the intermediary nodes that were not used in a long time.
| // an extension node can not have a leaf as child, so no need to check for that | ||
| _ = en.child.shouldCollapseChild(hexKey, tmc) | ||
| return false | ||
| } |
There was a problem hiding this comment.
so this func will always return false?
There was a problem hiding this comment.
Yes. Because we only collapse leaves and the child of an extension node can not be a leaf node, we never collapse the child of an extension node. I returned false instead of returning en.child.shouldCollapseChild(hexKey, tmc) directly just for this to be more obvious.
| return nil | ||
| } | ||
|
|
||
| func (bn *branchNode) shouldCollapseChild(hexKey []byte, tmc MetricsCollector) bool { |
There was a problem hiding this comment.
intended to return false on all paths?
There was a problem hiding this comment.
Yes. We only collapse leaf nodes, so only a leaf node can return true.
05f59ea
into
feat/collapse-trie-based-on-size
Reasoning behind the pull request
Proposed changes
collapseManagerwhich handles trie nodes collapsing. If the size in memory of the trie exceed the max allowed size, collapse the main trie leaves in LRU order.Testing procedure
Pre-requisites
Based on the Contributing Guidelines the PR author and the reviewers must check the following requirements are met:
featbranch created?featbranch merging, do all satellite projects have a proper tag insidego.mod?