triedb, core: polish code

This commit is contained in:
Gary Rong 2026-05-15 14:57:10 +08:00
parent e67fa13e34
commit 133ee263c8
7 changed files with 60 additions and 74 deletions

View file

@ -90,16 +90,17 @@ const (
stateHistoryStorageData = "storage.data" stateHistoryStorageData = "storage.data"
) )
// StateHistoryTailGroup is the tail group shared by all state history tables. // DefaultHistoryGroup is the tail group shared by all state/trienode history
const StateHistoryTailGroup = "history" // tables with tail pruning enabled.
const DefaultHistoryGroup = "history"
// stateFreezerTableConfigs configures the settings for tables in the state freezer. // stateFreezerTableConfigs configures the settings for tables in the state freezer.
var stateFreezerTableConfigs = map[string]freezerTableConfig{ var stateFreezerTableConfigs = map[string]freezerTableConfig{
stateHistoryMeta: {noSnappy: true, tailGroup: StateHistoryTailGroup}, stateHistoryMeta: {noSnappy: true, tailGroup: DefaultHistoryGroup},
stateHistoryAccountIndex: {noSnappy: false, tailGroup: StateHistoryTailGroup}, stateHistoryAccountIndex: {noSnappy: false, tailGroup: DefaultHistoryGroup},
stateHistoryStorageIndex: {noSnappy: false, tailGroup: StateHistoryTailGroup}, stateHistoryStorageIndex: {noSnappy: false, tailGroup: DefaultHistoryGroup},
stateHistoryAccountData: {noSnappy: false, tailGroup: StateHistoryTailGroup}, stateHistoryAccountData: {noSnappy: false, tailGroup: DefaultHistoryGroup},
stateHistoryStorageData: {noSnappy: false, tailGroup: StateHistoryTailGroup}, stateHistoryStorageData: {noSnappy: false, tailGroup: DefaultHistoryGroup},
} }
const ( const (
@ -108,18 +109,15 @@ const (
trienodeHistoryValueSectionTable = "trienode.value" 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. // trienodeFreezerTableConfigs configures the settings for tables in the trienode freezer.
var trienodeFreezerTableConfigs = map[string]freezerTableConfig{ var trienodeFreezerTableConfigs = map[string]freezerTableConfig{
trienodeHistoryHeaderTable: {noSnappy: false, tailGroup: TrienodeHistoryTailGroup}, trienodeHistoryHeaderTable: {noSnappy: false, tailGroup: DefaultHistoryGroup},
// Disable snappy compression to allow efficient partial read. // 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. // 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. // The list of identifiers of ancient stores.

View file

@ -59,7 +59,8 @@ const freezerTableSize = 2 * 1000 * 1000 * 1000
// - The in-order data ensures that disk reads are always optimized. // - The in-order data ensures that disk reads are always optimized.
type Freezer struct { type Freezer struct {
datadir string 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 // This lock synchronizes writers and the truncate operation, as well as
// the "atomic" (batched) read operations. // the "atomic" (batched) read operations.
@ -117,6 +118,7 @@ func NewFreezer(datadir string, namespace string, readonly bool, maxTableSize ui
datadir: datadir, datadir: datadir,
readonly: readonly, readonly: readonly,
tables: make(map[string]*freezerTable), tables: make(map[string]*freezerTable),
tails: make(map[string]*atomic.Uint64),
instanceLock: lock, instanceLock: lock,
} }
@ -216,32 +218,18 @@ func (f *Freezer) Ancients() (uint64, error) {
} }
// Tail returns the lowest accessible item index for the given tail group. // 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 // All tables sharing this group agree on the tail; an empty group name
// refers to non-prunable tables and always returns 0. // refers to non-prunable tables and always returns 0. Unknown groups return
// an error.
func (f *Freezer) Tail(group string) (uint64, error) { func (f *Freezer) Tail(group string) (uint64, error) {
if group == "" { if group == "" {
return 0, nil return 0, nil
} }
var ( tail, ok := f.tails[group]
tail uint64 if !ok {
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 {
return 0, fmt.Errorf("unknown tail group: %q", group) 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. // 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 == "" { if group == "" {
return 0, errors.New("empty tail 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() f.writeLock.Lock()
defer f.writeLock.Unlock() defer f.writeLock.Unlock()
var ( prev := cached.Load()
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)
}
for _, table := range f.tables { for _, table := range f.tables {
if table.config.tailGroup != group { if table.config.tailGroup != group {
continue continue
@ -360,6 +337,9 @@ func (f *Freezer) TruncateTail(group string, tail uint64) (uint64, error) {
return 0, err return 0, err
} }
} }
if tail > prev {
cached.Store(tail)
}
// Update the head if the requested tail exceeds the current head. // Update the head if the requested tail exceeds the current head.
if f.head.Load() < tail { if f.head.Load() < tail {
f.head.Store(tail) f.head.Store(tail)
@ -388,11 +368,12 @@ func (f *Freezer) validate() error {
return nil return nil
} }
var ( var (
head uint64 head uint64
headSet bool headSet bool
groupTails = make(map[string]uint64) tails = make(map[string]uint64)
) )
for kind, table := range f.tables { for kind, table := range f.tables {
// Validate the table head
items := table.items.Load() items := table.items.Load()
if !headSet { if !headSet {
head = items head = items
@ -400,6 +381,7 @@ func (f *Freezer) validate() error {
} else if items != head { } else if items != head {
return fmt.Errorf("freezer table %s has a differing head: %d != %d", kind, 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.config.tailGroup == "" {
if table.itemHidden.Load() != 0 { if table.itemHidden.Load() != 0 {
return fmt.Errorf("non-prunable freezer table '%s' has a non-zero tail: %d", kind, table.itemHidden.Load()) 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 continue
} }
hidden := table.itemHidden.Load() hidden := table.itemHidden.Load()
if t, ok := groupTails[table.config.tailGroup]; ok { if t, ok := tails[table.config.tailGroup]; ok {
if t != hidden { if t != hidden {
return fmt.Errorf("freezer table %s has differing tail in group %q: %d != %d", kind, table.config.tailGroup, hidden, t) return fmt.Errorf("freezer table %s has differing tail in group %q: %d != %d", kind, table.config.tailGroup, hidden, t)
} }
} else { } else {
groupTails[table.config.tailGroup] = hidden tails[table.config.tailGroup] = hidden
} }
} }
f.head.Store(head) f.head.Store(head)
for group, tail := range tails {
counter := new(atomic.Uint64)
counter.Store(tail)
f.tails[group] = counter
}
return nil return nil
} }
@ -463,7 +451,7 @@ func (f *Freezer) repair() error {
} }
// Per-group tail alignment: take the maximum tail in each group and apply // 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. // 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 { for kind, table := range f.tables {
if table.config.tailGroup == "" { if table.config.tailGroup == "" {
if table.itemHidden.Load() != 0 { if table.itemHidden.Load() != 0 {
@ -472,18 +460,24 @@ func (f *Freezer) repair() error {
continue continue
} }
hidden := table.itemHidden.Load() hidden := table.itemHidden.Load()
if t, ok := groupTails[table.config.tailGroup]; !ok || hidden > t { if t, ok := tails[table.config.tailGroup]; !ok || hidden > t {
groupTails[table.config.tailGroup] = hidden tails[table.config.tailGroup] = hidden
} }
} }
for _, table := range f.tables { for _, table := range f.tables {
if table.config.tailGroup == "" { if table.config.tailGroup == "" {
continue continue
} }
if err := table.truncateTail(groupTails[table.config.tailGroup]); err != nil { if err := table.truncateTail(tails[table.config.tailGroup]); err != nil {
return err return err
} }
} }
f.head.Store(head) f.head.Store(head)
for group, tail := range tails {
counter := new(atomic.Uint64)
counter.Store(tail)
f.tails[group] = counter
}
return nil return nil
} }

View file

@ -378,7 +378,7 @@ func (dl *diskLayer) writeHistory(typ historyType, diff *diffLayer) (bool, error
if limit == 0 { if limit == 0 {
return false, nil return false, nil
} }
tail, err := freezer.Tail(rawdb.StateHistoryTailGroup) tail, err := freezer.Tail(rawdb.DefaultHistoryGroup)
if err != nil { if err != nil {
return false, err return false, err
} // firstID = tail+1 } // firstID = tail+1

View file

@ -273,7 +273,7 @@ func truncateFromHead(store ethdb.AncientStore, typ historyType, nhead uint64) (
if err != nil { if err != nil {
return 0, err return 0, err
} }
otail, err := store.Tail(rawdb.StateHistoryTailGroup) otail, err := store.Tail(rawdb.DefaultHistoryGroup)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -303,13 +303,7 @@ func truncateFromTail(store ethdb.AncientStore, typ historyType, ntail uint64) (
if err != nil { if err != nil {
return 0, err return 0, err
} }
var group string otail, err := store.Tail(rawdb.DefaultHistoryGroup)
if typ == typeStateHistory {
group = rawdb.StateHistoryTailGroup
} else {
group = rawdb.TrienodeHistoryTailGroup
}
otail, err := store.Tail(group)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -321,7 +315,7 @@ func truncateFromTail(store ethdb.AncientStore, typ historyType, ntail uint64) (
if otail == ntail { if otail == ntail {
return 0, nil return 0, nil
} }
otail, err = store.TruncateTail(group, ntail) otail, err = store.TruncateTail(rawdb.DefaultHistoryGroup, ntail)
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -436,7 +430,7 @@ func repairHistory(db ethdb.Database, isUBT bool, readOnly bool, stateID uint64,
truncTo = min(truncTo, thead) truncTo = min(truncTo, thead)
} else { } else {
if thead == 0 { if thead == 0 {
_, err = trienodes.TruncateTail(rawdb.TrienodeHistoryTailGroup, stateID) _, err = trienodes.TruncateTail(rawdb.DefaultHistoryGroup, stateID)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }

View file

@ -542,7 +542,7 @@ func (i *indexIniter) run(recover bool) {
// next returns the ID of the next state history to be indexed. // next returns the ID of the next state history to be indexed.
func (i *indexIniter) next() (uint64, error) { func (i *indexIniter) next() (uint64, error) {
tail, err := i.freezer.Tail(rawdb.StateHistoryTailGroup) tail, err := i.freezer.Tail(rawdb.DefaultHistoryGroup)
if err != nil { if err != nil {
return 0, err return 0, err
} }

View file

@ -38,7 +38,7 @@ type HistoryStats struct {
// sanitizeRange limits the given range to fit within the local history store. // sanitizeRange limits the given range to fit within the local history store.
func sanitizeRange(start, end uint64, freezer ethdb.AncientReader) (uint64, uint64, error) { func sanitizeRange(start, end uint64, freezer ethdb.AncientReader) (uint64, uint64, error) {
// Load the id of the first history object in local store. // 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 { if err != nil {
return 0, 0, err 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. // historyRange returns the block number range of local state histories.
func historyRange(freezer ethdb.AncientReader) (uint64, uint64, error) { func historyRange(freezer ethdb.AncientReader) (uint64, uint64, error) {
// Load the id of the first history object in local store. // 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 { if err != nil {
return 0, 0, err return 0, 0, err
} }

View file

@ -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) return 0, fmt.Errorf("unsupported history type: %d, want: %v", toHistoryType(state.typ), exptyp)
} }
// firstID = tail+1 // firstID = tail+1
tail, err := freezer.Tail(rawdb.StateHistoryTailGroup) tail, err := freezer.Tail(rawdb.DefaultHistoryGroup)
if err != nil { if err != nil {
return 0, err return 0, err
} }