From 133ee263c881447d150e4755b146ce0fa0e4b5b3 Mon Sep 17 00:00:00 2001 From: Gary Rong Date: Fri, 15 May 2026 14:57:10 +0800 Subject: [PATCH] triedb, core: polish code --- core/rawdb/ancient_scheme.go | 24 ++++----- core/rawdb/freezer.go | 86 +++++++++++++++----------------- triedb/pathdb/disklayer.go | 2 +- triedb/pathdb/history.go | 14 ++---- triedb/pathdb/history_indexer.go | 2 +- triedb/pathdb/history_inspect.go | 4 +- triedb/pathdb/history_reader.go | 2 +- 7 files changed, 60 insertions(+), 74 deletions(-) diff --git a/core/rawdb/ancient_scheme.go b/core/rawdb/ancient_scheme.go index d6097a9193..9ee8f9d3d2 100644 --- a/core/rawdb/ancient_scheme.go +++ b/core/rawdb/ancient_scheme.go @@ -90,16 +90,17 @@ const ( stateHistoryStorageData = "storage.data" ) -// StateHistoryTailGroup is the tail group shared by all state history tables. -const StateHistoryTailGroup = "history" +// DefaultHistoryGroup is the tail group shared by all state/trienode history +// tables with tail pruning enabled. +const DefaultHistoryGroup = "history" // stateFreezerTableConfigs configures the settings for tables in the state freezer. var stateFreezerTableConfigs = map[string]freezerTableConfig{ - stateHistoryMeta: {noSnappy: true, tailGroup: StateHistoryTailGroup}, - stateHistoryAccountIndex: {noSnappy: false, tailGroup: StateHistoryTailGroup}, - stateHistoryStorageIndex: {noSnappy: false, tailGroup: StateHistoryTailGroup}, - stateHistoryAccountData: {noSnappy: false, tailGroup: StateHistoryTailGroup}, - stateHistoryStorageData: {noSnappy: false, tailGroup: StateHistoryTailGroup}, + stateHistoryMeta: {noSnappy: true, tailGroup: DefaultHistoryGroup}, + stateHistoryAccountIndex: {noSnappy: false, tailGroup: DefaultHistoryGroup}, + stateHistoryStorageIndex: {noSnappy: false, tailGroup: DefaultHistoryGroup}, + stateHistoryAccountData: {noSnappy: false, tailGroup: DefaultHistoryGroup}, + stateHistoryStorageData: {noSnappy: false, tailGroup: DefaultHistoryGroup}, } const ( @@ -108,18 +109,15 @@ const ( trienodeHistoryValueSectionTable = "trienode.value" ) -// TrienodeHistoryTailGroup is the tail group shared by all trienode history tables. -const TrienodeHistoryTailGroup = "history" - // trienodeFreezerTableConfigs configures the settings for tables in the trienode freezer. var trienodeFreezerTableConfigs = map[string]freezerTableConfig{ - trienodeHistoryHeaderTable: {noSnappy: false, tailGroup: TrienodeHistoryTailGroup}, + trienodeHistoryHeaderTable: {noSnappy: false, tailGroup: DefaultHistoryGroup}, // Disable snappy compression to allow efficient partial read. - trienodeHistoryKeySectionTable: {noSnappy: true, tailGroup: TrienodeHistoryTailGroup}, + trienodeHistoryKeySectionTable: {noSnappy: true, tailGroup: DefaultHistoryGroup}, // Disable snappy compression to allow efficient partial read. - trienodeHistoryValueSectionTable: {noSnappy: true, tailGroup: TrienodeHistoryTailGroup}, + trienodeHistoryValueSectionTable: {noSnappy: true, tailGroup: DefaultHistoryGroup}, } // The list of identifiers of ancient stores. diff --git a/core/rawdb/freezer.go b/core/rawdb/freezer.go index 7280bf9179..4fa613fbbf 100644 --- a/core/rawdb/freezer.go +++ b/core/rawdb/freezer.go @@ -59,7 +59,8 @@ const freezerTableSize = 2 * 1000 * 1000 * 1000 // - The in-order data ensures that disk reads are always optimized. type Freezer struct { datadir string - head atomic.Uint64 // Number of items stored (including items removed from tail) + head atomic.Uint64 // Number of items stored (including items removed from tail) + tails map[string]*atomic.Uint64 // Per-group tail cache, keyed by tail group name // This lock synchronizes writers and the truncate operation, as well as // the "atomic" (batched) read operations. @@ -117,6 +118,7 @@ func NewFreezer(datadir string, namespace string, readonly bool, maxTableSize ui datadir: datadir, readonly: readonly, tables: make(map[string]*freezerTable), + tails: make(map[string]*atomic.Uint64), instanceLock: lock, } @@ -216,32 +218,18 @@ func (f *Freezer) Ancients() (uint64, error) { } // Tail returns the lowest accessible item index for the given tail group. -// All tables sharing this group must agree on the tail; an empty group name -// refers to non-prunable tables and always returns 0. +// All tables sharing this group agree on the tail; an empty group name +// refers to non-prunable tables and always returns 0. Unknown groups return +// an error. func (f *Freezer) Tail(group string) (uint64, error) { if group == "" { return 0, nil } - var ( - tail uint64 - found bool - ) - for _, table := range f.tables { - if table.config.tailGroup != group { - continue - } - h := table.itemHidden.Load() - if !found { - tail = h - found = true - } else if h != tail { - return 0, fmt.Errorf("inconsistent tail in group %q: %d vs %d", group, h, tail) - } - } - if !found { + tail, ok := f.tails[group] + if !ok { return 0, fmt.Errorf("unknown tail group: %q", group) } - return tail, nil + return tail.Load(), nil } // AncientSize returns the ancient size of the specified category. @@ -333,25 +321,14 @@ func (f *Freezer) TruncateTail(group string, tail uint64) (uint64, error) { if group == "" { return 0, errors.New("empty tail group") } + cached, ok := f.tails[group] + if !ok { + return 0, fmt.Errorf("unknown tail group: %q", group) + } f.writeLock.Lock() defer f.writeLock.Unlock() - var ( - prev uint64 - found bool - ) - for _, table := range f.tables { - if table.config.tailGroup != group { - continue - } - if !found { - prev = table.itemHidden.Load() - found = true - } - } - if !found { - return 0, fmt.Errorf("unknown tail group: %q", group) - } + prev := cached.Load() for _, table := range f.tables { if table.config.tailGroup != group { continue @@ -360,6 +337,9 @@ func (f *Freezer) TruncateTail(group string, tail uint64) (uint64, error) { return 0, err } } + if tail > prev { + cached.Store(tail) + } // Update the head if the requested tail exceeds the current head. if f.head.Load() < tail { f.head.Store(tail) @@ -388,11 +368,12 @@ func (f *Freezer) validate() error { return nil } var ( - head uint64 - headSet bool - groupTails = make(map[string]uint64) + head uint64 + headSet bool + tails = make(map[string]uint64) ) for kind, table := range f.tables { + // Validate the table head items := table.items.Load() if !headSet { head = items @@ -400,6 +381,7 @@ func (f *Freezer) validate() error { } else if items != head { return fmt.Errorf("freezer table %s has a differing head: %d != %d", kind, items, head) } + // Validate the table tail if table.config.tailGroup == "" { if table.itemHidden.Load() != 0 { return fmt.Errorf("non-prunable freezer table '%s' has a non-zero tail: %d", kind, table.itemHidden.Load()) @@ -407,15 +389,21 @@ func (f *Freezer) validate() error { continue } hidden := table.itemHidden.Load() - if t, ok := groupTails[table.config.tailGroup]; ok { + if t, ok := tails[table.config.tailGroup]; ok { if t != hidden { return fmt.Errorf("freezer table %s has differing tail in group %q: %d != %d", kind, table.config.tailGroup, hidden, t) } } else { - groupTails[table.config.tailGroup] = hidden + tails[table.config.tailGroup] = hidden } } f.head.Store(head) + + for group, tail := range tails { + counter := new(atomic.Uint64) + counter.Store(tail) + f.tails[group] = counter + } return nil } @@ -463,7 +451,7 @@ func (f *Freezer) repair() error { } // Per-group tail alignment: take the maximum tail in each group and apply // it to all members. Non-prunable tables must remain at tail 0. - groupTails := make(map[string]uint64) + tails := make(map[string]uint64) for kind, table := range f.tables { if table.config.tailGroup == "" { if table.itemHidden.Load() != 0 { @@ -472,18 +460,24 @@ func (f *Freezer) repair() error { continue } hidden := table.itemHidden.Load() - if t, ok := groupTails[table.config.tailGroup]; !ok || hidden > t { - groupTails[table.config.tailGroup] = hidden + if t, ok := tails[table.config.tailGroup]; !ok || hidden > t { + tails[table.config.tailGroup] = hidden } } for _, table := range f.tables { if table.config.tailGroup == "" { continue } - if err := table.truncateTail(groupTails[table.config.tailGroup]); err != nil { + if err := table.truncateTail(tails[table.config.tailGroup]); err != nil { return err } } f.head.Store(head) + + for group, tail := range tails { + counter := new(atomic.Uint64) + counter.Store(tail) + f.tails[group] = counter + } return nil } diff --git a/triedb/pathdb/disklayer.go b/triedb/pathdb/disklayer.go index 47a882446a..8c0a751932 100644 --- a/triedb/pathdb/disklayer.go +++ b/triedb/pathdb/disklayer.go @@ -378,7 +378,7 @@ func (dl *diskLayer) writeHistory(typ historyType, diff *diffLayer) (bool, error if limit == 0 { return false, nil } - tail, err := freezer.Tail(rawdb.StateHistoryTailGroup) + tail, err := freezer.Tail(rawdb.DefaultHistoryGroup) if err != nil { return false, err } // firstID = tail+1 diff --git a/triedb/pathdb/history.go b/triedb/pathdb/history.go index 4668d6f3a4..55ec29e4f0 100644 --- a/triedb/pathdb/history.go +++ b/triedb/pathdb/history.go @@ -273,7 +273,7 @@ func truncateFromHead(store ethdb.AncientStore, typ historyType, nhead uint64) ( if err != nil { return 0, err } - otail, err := store.Tail(rawdb.StateHistoryTailGroup) + otail, err := store.Tail(rawdb.DefaultHistoryGroup) if err != nil { return 0, err } @@ -303,13 +303,7 @@ func truncateFromTail(store ethdb.AncientStore, typ historyType, ntail uint64) ( if err != nil { return 0, err } - var group string - if typ == typeStateHistory { - group = rawdb.StateHistoryTailGroup - } else { - group = rawdb.TrienodeHistoryTailGroup - } - otail, err := store.Tail(group) + otail, err := store.Tail(rawdb.DefaultHistoryGroup) if err != nil { return 0, err } @@ -321,7 +315,7 @@ func truncateFromTail(store ethdb.AncientStore, typ historyType, ntail uint64) ( if otail == ntail { return 0, nil } - otail, err = store.TruncateTail(group, ntail) + otail, err = store.TruncateTail(rawdb.DefaultHistoryGroup, ntail) if err != nil { return 0, err } @@ -436,7 +430,7 @@ func repairHistory(db ethdb.Database, isUBT bool, readOnly bool, stateID uint64, truncTo = min(truncTo, thead) } else { if thead == 0 { - _, err = trienodes.TruncateTail(rawdb.TrienodeHistoryTailGroup, stateID) + _, err = trienodes.TruncateTail(rawdb.DefaultHistoryGroup, stateID) if err != nil { return nil, nil, err } diff --git a/triedb/pathdb/history_indexer.go b/triedb/pathdb/history_indexer.go index 873990b6b5..3789fae19b 100644 --- a/triedb/pathdb/history_indexer.go +++ b/triedb/pathdb/history_indexer.go @@ -542,7 +542,7 @@ func (i *indexIniter) run(recover bool) { // next returns the ID of the next state history to be indexed. func (i *indexIniter) next() (uint64, error) { - tail, err := i.freezer.Tail(rawdb.StateHistoryTailGroup) + tail, err := i.freezer.Tail(rawdb.DefaultHistoryGroup) if err != nil { return 0, err } diff --git a/triedb/pathdb/history_inspect.go b/triedb/pathdb/history_inspect.go index c956295368..8b5624f441 100644 --- a/triedb/pathdb/history_inspect.go +++ b/triedb/pathdb/history_inspect.go @@ -38,7 +38,7 @@ type HistoryStats struct { // sanitizeRange limits the given range to fit within the local history store. func sanitizeRange(start, end uint64, freezer ethdb.AncientReader) (uint64, uint64, error) { // Load the id of the first history object in local store. - tail, err := freezer.Tail(rawdb.StateHistoryTailGroup) + tail, err := freezer.Tail(rawdb.DefaultHistoryGroup) if err != nil { return 0, 0, err } @@ -133,7 +133,7 @@ func storageHistory(freezer ethdb.AncientReader, address common.Address, slot co // historyRange returns the block number range of local state histories. func historyRange(freezer ethdb.AncientReader) (uint64, uint64, error) { // Load the id of the first history object in local store. - tail, err := freezer.Tail(rawdb.StateHistoryTailGroup) + tail, err := freezer.Tail(rawdb.DefaultHistoryGroup) if err != nil { return 0, 0, err } diff --git a/triedb/pathdb/history_reader.go b/triedb/pathdb/history_reader.go index 51536c8aae..1652e412eb 100644 --- a/triedb/pathdb/history_reader.go +++ b/triedb/pathdb/history_reader.go @@ -470,7 +470,7 @@ func checkStateAvail(state stateIdent, exptyp historyType, freezer ethdb.Ancient return 0, fmt.Errorf("unsupported history type: %d, want: %v", toHistoryType(state.typ), exptyp) } // firstID = tail+1 - tail, err := freezer.Tail(rawdb.StateHistoryTailGroup) + tail, err := freezer.Tail(rawdb.DefaultHistoryGroup) if err != nil { return 0, err }