core/rawdb: un-embed freezer instance in chainFreezer

This commit is contained in:
Felix Lange 2025-05-19 17:09:47 +02:00 committed by lightclient
parent cc914b49e0
commit 9b1b2f69b8
No known key found for this signature in database
GPG key ID: 657913021EF45A6A

View file

@ -44,7 +44,7 @@ const (
// feature. The background thread will keep moving ancient chain segments from // feature. The background thread will keep moving ancient chain segments from
// key-value database to flat files for saving space on live database. // key-value database to flat files for saving space on live database.
type chainFreezer struct { type chainFreezer struct {
ethdb.AncientStore // Ancient store for storing cold chain segment ancients ethdb.AncientStore // Ancient store for storing cold chain segment
// Optional Era database used as a backup for the pruned chain. // Optional Era database used as a backup for the pruned chain.
eradb *eradb.Store eradb *eradb.Store
@ -63,7 +63,7 @@ type chainFreezer struct {
func newChainFreezer(datadir string, namespace string, readonly bool, eraDir string) (*chainFreezer, error) { func newChainFreezer(datadir string, namespace string, readonly bool, eraDir string) (*chainFreezer, error) {
if datadir == "" { if datadir == "" {
return &chainFreezer{ return &chainFreezer{
AncientStore: NewMemoryFreezer(readonly, chainFreezerTableConfigs), ancients: NewMemoryFreezer(readonly, chainFreezerTableConfigs),
quit: make(chan struct{}), quit: make(chan struct{}),
trigger: make(chan chan struct{}), trigger: make(chan chan struct{}),
}, nil }, nil
@ -80,7 +80,7 @@ func newChainFreezer(datadir string, namespace string, readonly bool, eraDir str
} }
} }
return &chainFreezer{ return &chainFreezer{
AncientStore: freezer, ancients: freezer,
eradb: edb, eradb: edb,
quit: make(chan struct{}), quit: make(chan struct{}),
trigger: make(chan chan struct{}), trigger: make(chan chan struct{}),
@ -96,13 +96,10 @@ func (f *chainFreezer) Close() error {
} }
f.wg.Wait() f.wg.Wait()
var errs []error
if f.eradb != nil { if f.eradb != nil {
f.eradb.Close() f.eradb.Close()
} }
errs = append(errs, f.AncientStore.Close()) return f.ancients.Close()
return errors.Join(errs...)
} }
// readHeadNumber returns the number of chain head block. 0 is returned if the // readHeadNumber returns the number of chain head block. 0 is returned if the
@ -199,7 +196,7 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) {
log.Debug("Current full block not old enough to freeze", "err", err) log.Debug("Current full block not old enough to freeze", "err", err)
continue continue
} }
frozen, _ := f.Ancients() // no error will occur, safe to ignore frozen, _ := f.ancients.Ancients() // no error will occur, safe to ignore
// Short circuit if the blocks below threshold are already frozen. // Short circuit if the blocks below threshold are already frozen.
if frozen != 0 && frozen-1 >= threshold { if frozen != 0 && frozen-1 >= threshold {
@ -242,7 +239,7 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) {
// Wipe out side chains also and track dangling side chains // Wipe out side chains also and track dangling side chains
var dangling []common.Hash var dangling []common.Hash
frozen, _ = f.Ancients() // Needs reload after during freezeRange frozen, _ = f.ancients.Ancients() // Needs reload after during freezeRange
for number := first; number < frozen; number++ { for number := first; number < frozen; number++ {
// Always keep the genesis block in active database // Always keep the genesis block in active database
if number != 0 { if number != 0 {
@ -314,7 +311,7 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) {
func (f *chainFreezer) freezeRange(nfdb *nofreezedb, number, limit uint64) (hashes []common.Hash, err error) { func (f *chainFreezer) freezeRange(nfdb *nofreezedb, number, limit uint64) (hashes []common.Hash, err error) {
hashes = make([]common.Hash, 0, limit-number+1) hashes = make([]common.Hash, 0, limit-number+1)
_, err = f.ModifyAncients(func(op ethdb.AncientWriteOp) error { _, err = f.ancients.ModifyAncients(func(op ethdb.AncientWriteOp) error {
for ; number <= limit; number++ { for ; number <= limit; number++ {
// Retrieve all the components of the canonical block. // Retrieve all the components of the canonical block.
hash := ReadCanonicalHash(nfdb, number) hash := ReadCanonicalHash(nfdb, number)
@ -358,15 +355,15 @@ func (f *chainFreezer) Ancient(kind string, number uint64) ([]byte, error) {
// Lookup the entry in the underlying ancient store, assuming that // Lookup the entry in the underlying ancient store, assuming that
// headers and hashes are always available. // headers and hashes are always available.
if kind == ChainFreezerHeaderTable || kind == ChainFreezerHashTable { if kind == ChainFreezerHeaderTable || kind == ChainFreezerHashTable {
return f.AncientStore.Ancient(kind, number) return f.ancients.Ancient(kind, number)
} }
tail, err := f.Tail() tail, err := f.ancients.Tail()
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Lookup the entry in the underlying ancient store if it's not pruned // Lookup the entry in the underlying ancient store if it's not pruned
if number >= tail { if number >= tail {
return f.AncientStore.Ancient(kind, number) return f.ancients.Ancient(kind, number)
} }
// Lookup the entry in the optional era backend // Lookup the entry in the optional era backend
if f.eradb == nil { if f.eradb == nil {
@ -381,16 +378,46 @@ func (f *chainFreezer) Ancient(kind string, number uint64) ([]byte, error) {
return nil, errUnknownTable return nil, errUnknownTable
} }
// AncientRange retrieves multiple items in sequence, starting from the index 'start'. // ReadAncients executes an operation while preventing mutations to the freezer,
// It will return // i.e. if fn performs multiple reads, they will be consistent with each other.
// - at most 'count' items,
// - if maxBytes is specified: at least 1 item (even if exceeding the maxByteSize),
// but will otherwise return as many items as fit into maxByteSize.
// - if maxBytes is not specified, 'count' items will be returned if they are present.
func (f *chainFreezer) ReadAncients(fn func(ethdb.AncientReaderOp) error) (err error) { func (f *chainFreezer) ReadAncients(fn func(ethdb.AncientReaderOp) error) (err error) {
if store, ok := f.AncientStore.(*Freezer); ok { if store, ok := f.ancients.(*Freezer); ok {
store.writeLock.Lock() store.writeLock.Lock()
defer store.writeLock.Unlock() defer store.writeLock.Unlock()
} }
return fn(f) return fn(f)
} }
// Methods below are just pass-through to the underlying ancient store.
func (f *chainFreezer) Ancients() (uint64, error) {
return f.ancients.Ancients()
}
func (f *chainFreezer) Tail() (uint64, error) {
return f.ancients.Tail()
}
func (f *chainFreezer) AncientSize(kind string) (uint64, error) {
return f.ancients.AncientSize(kind)
}
func (f *chainFreezer) AncientRange(kind string, start, count, maxBytes uint64) ([][]byte, error) {
return f.ancients.AncientRange(kind, start, count, maxBytes)
}
func (f *chainFreezer) ModifyAncients(fn func(ethdb.AncientWriteOp) error) (int64, error) {
return f.ancients.ModifyAncients(fn)
}
func (f *chainFreezer) TruncateHead(items uint64) (uint64, error) {
return f.ancients.TruncateHead(items)
}
func (f *chainFreezer) TruncateTail(items uint64) (uint64, error) {
return f.ancients.TruncateTail(items)
}
func (f *chainFreezer) SyncAncient() error {
return f.ancients.SyncAncient()
}