trie: more refactoring

This commit is contained in:
lightclient 2026-02-18 04:44:01 +00:00
parent 9b4495b9a8
commit a596a0aba3
No known key found for this signature in database
GPG key ID: 91289C7FE4ADADBD
2 changed files with 101 additions and 123 deletions

View file

@ -300,9 +300,9 @@ func Summarize(dumpPath string, config *InspectConfig) error {
} }
} }
depthTop := newStorageTopN(config.TopN, compareStorageByDepth) depthTop := newStorageStatsTopN(config.TopN, compareStorageStatsByDepth)
totalTop := newStorageTopN(config.TopN, compareStorageByTotal) totalTop := newStorageStatsTopN(config.TopN, compareStorageStatsByTotal)
valueTop := newStorageTopN(config.TopN, compareStorageByValue) valueTop := newStorageStatsTopN(config.TopN, compareStorageStatsByValue)
summary := &inspectSummary{} summary := &inspectSummary{}
reader := bufio.NewReaderSize(file, 1<<20) reader := bufio.NewReaderSize(file, 1<<20)
@ -321,7 +321,7 @@ func Summarize(dumpPath string, config *InspectConfig) error {
} }
record := decodeDumpRecord(buf[:]) record := decodeDumpRecord(buf[:])
snapshot := newStorageSnapshot(record.Owner, record.Levels) snapshot := newStorageStats(record.Owner, record.Levels)
if record.Owner == (common.Hash{}) { if record.Owner == (common.Hash{}) {
summary.Account = snapshot summary.Account = snapshot
continue continue
@ -372,7 +372,7 @@ func decodeDumpRecord(raw []byte) dumpRecord {
return record return record
} }
type storageSnapshot struct { type storageStats struct {
Owner common.Hash Owner common.Hash
Levels [trieStatLevels]jsonLevel Levels [trieStatLevels]jsonLevel
Summary jsonLevel Summary jsonLevel
@ -380,8 +380,8 @@ type storageSnapshot struct {
TotalNodes uint64 TotalNodes uint64
} }
func newStorageSnapshot(owner common.Hash, levels [trieStatLevels]jsonLevel) *storageSnapshot { func newStorageStats(owner common.Hash, levels [trieStatLevels]jsonLevel) *storageStats {
snapshot := &storageSnapshot{Owner: owner, Levels: levels} snapshot := &storageStats{Owner: owner, Levels: levels}
for i := 0; i < trieStatLevels; i++ { for i := 0; i < trieStatLevels; i++ {
level := levels[i] level := levels[i]
if level.Short != 0 || level.Full != 0 || level.Value != 0 { if level.Short != 0 || level.Full != 0 || level.Value != 0 {
@ -395,7 +395,34 @@ func newStorageSnapshot(owner common.Hash, levels [trieStatLevels]jsonLevel) *st
return snapshot return snapshot
} }
func (s *storageSnapshot) toLevelStats() *LevelStats { func trimLevels(levels [trieStatLevels]jsonLevel) []jsonLevel {
n := len(levels)
for n > 0 && levels[n-1] == (jsonLevel{}) {
n--
}
return levels[:n]
}
func (s *storageStats) MarshalJSON() ([]byte, error) {
type jsonStorageSnapshot struct {
Owner common.Hash `json:"Owner"`
MaxDepth int `json:"MaxDepth"`
TotalNodes uint64 `json:"TotalNodes"`
ValueNodes uint64 `json:"ValueNodes"`
Levels []jsonLevel `json:"Levels"`
Summary jsonLevel `json:"Summary"`
}
return json.Marshal(jsonStorageSnapshot{
Owner: s.Owner,
MaxDepth: s.MaxDepth,
TotalNodes: s.TotalNodes,
ValueNodes: s.Summary.Value,
Levels: trimLevels(s.Levels),
Summary: s.Summary,
})
}
func (s *storageStats) toLevelStats() *LevelStats {
stats := NewLevelStats() stats := NewLevelStats()
for i := 0; i < trieStatLevels; i++ { for i := 0; i < trieStatLevels; i++ {
stats.level[i].short.Store(s.Levels[i].Short) stats.level[i].short.Store(s.Levels[i].Short)
@ -405,45 +432,45 @@ func (s *storageSnapshot) toLevelStats() *LevelStats {
return stats return stats
} }
type storageCompare func(a, b *storageSnapshot) int type storageStatsCompare func(a, b *storageStats) int
type topStorage struct { type storageStatsTopN struct {
limit int limit int
cmp storageCompare cmp storageStatsCompare
heap storageHeap heap storageStatsHeap
} }
type storageHeap struct { type storageStatsHeap struct {
items []*storageSnapshot items []*storageStats
cmp storageCompare cmp storageStatsCompare
} }
func (h storageHeap) Len() int { return len(h.items) } func (h storageStatsHeap) Len() int { return len(h.items) }
func (h storageHeap) Less(i, j int) bool { func (h storageStatsHeap) Less(i, j int) bool {
// Keep the weakest entry at the root (min-heap semantics). // Keep the weakest entry at the root (min-heap semantics).
return h.cmp(h.items[i], h.items[j]) < 0 return h.cmp(h.items[i], h.items[j]) < 0
} }
func (h storageHeap) Swap(i, j int) { h.items[i], h.items[j] = h.items[j], h.items[i] } func (h storageStatsHeap) Swap(i, j int) { h.items[i], h.items[j] = h.items[j], h.items[i] }
func (h *storageHeap) Push(x any) { func (h *storageStatsHeap) Push(x any) {
h.items = append(h.items, x.(*storageSnapshot)) h.items = append(h.items, x.(*storageStats))
} }
func (h *storageHeap) Pop() any { func (h *storageStatsHeap) Pop() any {
item := h.items[len(h.items)-1] item := h.items[len(h.items)-1]
h.items = h.items[:len(h.items)-1] h.items = h.items[:len(h.items)-1]
return item return item
} }
func newStorageTopN(limit int, cmp storageCompare) *topStorage { func newStorageStatsTopN(limit int, cmp storageStatsCompare) *storageStatsTopN {
h := storageHeap{cmp: cmp} h := storageStatsHeap{cmp: cmp}
heap.Init(&h) heap.Init(&h)
return &topStorage{limit: limit, cmp: cmp, heap: h} return &storageStatsTopN{limit: limit, cmp: cmp, heap: h}
} }
func (t *topStorage) TryInsert(item *storageSnapshot) { func (t *storageStatsTopN) TryInsert(item *storageStats) {
if t.limit <= 0 { if t.limit <= 0 {
return return
} }
@ -458,13 +485,13 @@ func (t *topStorage) TryInsert(item *storageSnapshot) {
heap.Push(&t.heap, item) heap.Push(&t.heap, item)
} }
func (t *topStorage) Sorted() []*storageSnapshot { func (t *storageStatsTopN) Sorted() []*storageStats {
out := append([]*storageSnapshot(nil), t.heap.items...) out := append([]*storageStats(nil), t.heap.items...)
sort.Slice(out, func(i, j int) bool { return t.cmp(out[i], out[j]) > 0 }) sort.Slice(out, func(i, j int) bool { return t.cmp(out[i], out[j]) > 0 })
return out return out
} }
func compareStorageByDepth(a, b *storageSnapshot) int { func compareStorageStatsByDepth(a, b *storageStats) int {
return cmp.Or( return cmp.Or(
cmp.Compare(a.MaxDepth, b.MaxDepth), cmp.Compare(a.MaxDepth, b.MaxDepth),
cmp.Compare(a.TotalNodes, b.TotalNodes), cmp.Compare(a.TotalNodes, b.TotalNodes),
@ -473,7 +500,7 @@ func compareStorageByDepth(a, b *storageSnapshot) int {
) )
} }
func compareStorageByTotal(a, b *storageSnapshot) int { func compareStorageStatsByTotal(a, b *storageStats) int {
return cmp.Or( return cmp.Or(
cmp.Compare(a.TotalNodes, b.TotalNodes), cmp.Compare(a.TotalNodes, b.TotalNodes),
cmp.Compare(a.MaxDepth, b.MaxDepth), cmp.Compare(a.MaxDepth, b.MaxDepth),
@ -482,7 +509,7 @@ func compareStorageByTotal(a, b *storageSnapshot) int {
) )
} }
func compareStorageByValue(a, b *storageSnapshot) int { func compareStorageStatsByValue(a, b *storageStats) int {
return cmp.Or( return cmp.Or(
cmp.Compare(a.Summary.Value, b.Summary.Value), cmp.Compare(a.Summary.Value, b.Summary.Value),
cmp.Compare(a.MaxDepth, b.MaxDepth), cmp.Compare(a.MaxDepth, b.MaxDepth),
@ -492,13 +519,13 @@ func compareStorageByValue(a, b *storageSnapshot) int {
} }
type inspectSummary struct { type inspectSummary struct {
Account *storageSnapshot Account *storageStats
StorageCount uint64 StorageCount uint64
StorageTotals jsonLevel StorageTotals jsonLevel
DepthHistogram [trieStatLevels]uint64 DepthHistogram [trieStatLevels]uint64
TopByDepth []*storageSnapshot TopByDepth []*storageStats
TopByTotalNodes []*storageSnapshot TopByTotalNodes []*storageStats
TopByValueNodes []*storageSnapshot TopByValueNodes []*storageStats
} }
func (s *inspectSummary) display() { func (s *inspectSummary) display() {
@ -526,7 +553,7 @@ func (s *inspectSummary) display() {
s.displayTop("Top storage tries by value (slot) count", s.TopByValueNodes) s.displayTop("Top storage tries by value (slot) count", s.TopByValueNodes)
} }
func (s *inspectSummary) displayTop(title string, list []*storageSnapshot) { func (s *inspectSummary) displayTop(title string, list []*storageStats) {
fmt.Println(title) fmt.Println(title)
if len(list) == 0 { if len(list) == 0 {
fmt.Println("No storage tries found") fmt.Println("No storage tries found")
@ -539,6 +566,41 @@ func (s *inspectSummary) displayTop(title string, list []*storageSnapshot) {
} }
} }
func (s *inspectSummary) MarshalJSON() ([]byte, error) {
type jsonAccountTrie struct {
Name string `json:"Name"`
Levels []jsonLevel `json:"Levels"`
Summary jsonLevel `json:"Summary"`
}
type jsonStorageSummary struct {
TotalStorageTries uint64 `json:"TotalStorageTries"`
Totals jsonLevel `json:"Totals"`
DepthHistogram [trieStatLevels]uint64 `json:"DepthHistogram"`
}
type jsonInspectSummary struct {
AccountTrie jsonAccountTrie `json:"AccountTrie"`
StorageSummary jsonStorageSummary `json:"StorageSummary"`
TopByDepth []*storageStats `json:"TopByDepth"`
TopByTotalNodes []*storageStats `json:"TopByTotalNodes"`
TopByValueNodes []*storageStats `json:"TopByValueNodes"`
}
return json.Marshal(jsonInspectSummary{
AccountTrie: jsonAccountTrie{
Name: "account trie",
Levels: trimLevels(s.Account.Levels),
Summary: s.Account.Summary,
},
StorageSummary: jsonStorageSummary{
TotalStorageTries: s.StorageCount,
Totals: s.StorageTotals,
DepthHistogram: s.DepthHistogram,
},
TopByDepth: s.TopByDepth,
TopByTotalNodes: s.TopByTotalNodes,
TopByValueNodes: s.TopByValueNodes,
})
}
func (s *inspectSummary) writeJSON(path string) error { func (s *inspectSummary) writeJSON(path string) error {
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644) file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644)
if err != nil { if err != nil {
@ -548,61 +610,7 @@ func (s *inspectSummary) writeJSON(path string) error {
enc := json.NewEncoder(file) enc := json.NewEncoder(file)
enc.SetIndent("", " ") enc.SetIndent("", " ")
return enc.Encode(s.toJSON()) return enc.Encode(s)
}
func (s *inspectSummary) toJSON() *jsonSummary {
jsonSummary := &jsonSummary{
AccountTrie: newJsonStat(s.Account.toLevelStats(), "account trie"),
StorageSummary: jsonStorageSummary{
TotalStorageTries: s.StorageCount,
Totals: s.StorageTotals,
DepthHistogram: s.DepthHistogram,
},
TopByDepth: snapshotsToJSON(s.TopByDepth),
TopByTotalNodes: snapshotsToJSON(s.TopByTotalNodes),
TopByValueNodes: snapshotsToJSON(s.TopByValueNodes),
}
return jsonSummary
}
type jsonSummary struct {
AccountTrie *jsonStat
StorageSummary jsonStorageSummary
TopByDepth []jsonStorageStat
TopByTotalNodes []jsonStorageStat
TopByValueNodes []jsonStorageStat
}
type jsonStorageSummary struct {
TotalStorageTries uint64
Totals jsonLevel
DepthHistogram [trieStatLevels]uint64
}
type jsonStorageStat struct {
Owner string
MaxDepth int
TotalNodes uint64
ValueNodes uint64
Levels []jsonLevel
Summary jsonLevel
}
func snapshotsToJSON(list []*storageSnapshot) []jsonStorageStat {
out := make([]jsonStorageStat, 0, len(list))
for _, item := range list {
stat := newJsonStat(item.toLevelStats(), item.Owner.Hex())
out = append(out, jsonStorageStat{
Owner: item.Owner.Hex(),
MaxDepth: item.MaxDepth,
TotalNodes: item.TotalNodes,
ValueNodes: item.Summary.Value,
Levels: stat.Levels,
Summary: stat.Summary,
})
}
return out
} }
// display will print a table displaying the trie's node statistics. // display will print a table displaying the trie's node statistics.
@ -629,7 +637,7 @@ func (s *LevelStats) display(title string) {
table.SetFooter([]string{"Total", "", fmt.Sprint(short), fmt.Sprint(full), fmt.Sprint(value)}) table.SetFooter([]string{"Total", "", fmt.Sprint(short), fmt.Sprint(full), fmt.Sprint(value)})
table.Render() table.Render()
fmt.Print(b.String()) fmt.Print(b.String())
fmt.Println("Max depth", s.maxDepth()) fmt.Println("Max depth", s.MaxDepth())
fmt.Println() fmt.Println()
} }
@ -638,28 +646,3 @@ type jsonLevel struct {
Full uint64 Full uint64
Value uint64 Value uint64
} }
type jsonStat struct {
Name string
Levels []jsonLevel
Summary jsonLevel
}
func newJsonStat(s *LevelStats, name string) *jsonStat {
ret := jsonStat{Name: name, Summary: jsonLevel{}}
for i := 0; i < len(s.level); i++ {
if s.level[i].empty() {
continue
}
level := jsonLevel{
Short: s.level[i].short.Load(),
Full: s.level[i].full.Load(),
Value: s.level[i].value.Load(),
}
ret.Summary.Full += level.Full
ret.Summary.Short += level.Short
ret.Summary.Value += level.Value
ret.Levels = append(ret.Levels, level)
}
return &ret
}

View file

@ -36,9 +36,9 @@ func NewLevelStats() *LevelStats {
return &LevelStats{} return &LevelStats{}
} }
// maxDepth iterates each level and finds the deepest level with at least one // MaxDepth iterates each level and finds the deepest level with at least one
// trie node. // trie node.
func (s *LevelStats) maxDepth() int { func (s *LevelStats) MaxDepth() int {
depth := 0 depth := 0
for i := range s.level { for i := range s.level {
if s.level[i].short.Load() != 0 || s.level[i].full.Load() != 0 || s.level[i].value.Load() != 0 { if s.level[i].short.Load() != 0 || s.level[i].full.Load() != 0 || s.level[i].value.Load() != 0 {
@ -48,11 +48,6 @@ func (s *LevelStats) maxDepth() int {
return depth return depth
} }
// MaxDepth returns the deepest level with at least one trie node.
func (s *LevelStats) MaxDepth() int {
return s.maxDepth()
}
// add increases the node count by one for the specified node type and depth. // add increases the node count by one for the specified node type and depth.
func (s *LevelStats) add(n node, depth uint32) { func (s *LevelStats) add(n node, depth uint32) {
d := int(depth) d := int(depth)