mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-25 14:16:44 +00:00
use glob instead of scanning
This commit is contained in:
parent
228e410d4c
commit
583837bfdd
3 changed files with 37 additions and 61 deletions
|
|
@ -20,9 +20,9 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path/filepath"
|
||||||
"sync"
|
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common/lru"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/internal/era"
|
"github.com/ethereum/go-ethereum/internal/era"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
|
@ -30,12 +30,12 @@ import (
|
||||||
|
|
||||||
type EraDatabase struct {
|
type EraDatabase struct {
|
||||||
datadir string
|
datadir string
|
||||||
table map[uint64]*era.Era
|
network string
|
||||||
mu sync.RWMutex
|
cache *lru.Cache[uint64, *era.Era]
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new EraDatabase instance.
|
// New creates a new EraDatabase instance.
|
||||||
func New(datadir string) (*EraDatabase, error) {
|
func New(datadir, network string) (*EraDatabase, error) {
|
||||||
// Ensure the datadir is not a symbolic link if it exists.
|
// Ensure the datadir is not a symbolic link if it exists.
|
||||||
if info, err := os.Lstat(datadir); !os.IsNotExist(err) {
|
if info, err := os.Lstat(datadir); !os.IsNotExist(err) {
|
||||||
if info == nil {
|
if info == nil {
|
||||||
|
|
@ -50,28 +50,9 @@ func New(datadir string) (*EraDatabase, error) {
|
||||||
if err := os.MkdirAll(datadir, 0755); err != nil {
|
if err := os.MkdirAll(datadir, 0755); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
db := &EraDatabase{datadir: datadir, network: network, cache: lru.NewCache[uint64, *era.Era](50)}
|
||||||
log.Info("Opened erastore", "datadir", datadir)
|
log.Info("Opened erastore", "datadir", datadir)
|
||||||
return &EraDatabase{datadir: datadir, table: make(map[uint64]*era.Era)}, nil
|
return db, nil
|
||||||
}
|
|
||||||
|
|
||||||
// scan returns a list of all era1 files in the datadir.
|
|
||||||
func (db *EraDatabase) scan() ([]string, error) {
|
|
||||||
entries, err := os.ReadDir(db.datadir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var files []string
|
|
||||||
for _, entry := range entries {
|
|
||||||
if entry.IsDir() || entry.Type()&os.ModeSymlink != 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Skip files that are not era1 files.
|
|
||||||
if path.Ext(entry.Name()) != ".era1" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
files = append(files, entry.Name())
|
|
||||||
}
|
|
||||||
return files, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *EraDatabase) openEra(name string) (*era.Era, error) {
|
func (db *EraDatabase) openEra(name string) (*era.Era, error) {
|
||||||
|
|
@ -86,46 +67,46 @@ func (db *EraDatabase) openEra(name string) (*era.Era, error) {
|
||||||
if e.Start()%uint64(era.MaxEra1Size) != 0 {
|
if e.Start()%uint64(era.MaxEra1Size) != 0 {
|
||||||
return nil, fmt.Errorf("pre-merge era1 file has invalid boundary. %d %% %d != 0", e.Start(), era.MaxEra1Size)
|
return nil, fmt.Errorf("pre-merge era1 file has invalid boundary. %d %% %d != 0", e.Start(), era.MaxEra1Size)
|
||||||
}
|
}
|
||||||
epoch := e.Start() / uint64(era.MaxEra1Size)
|
|
||||||
db.mu.Lock()
|
|
||||||
db.table[epoch] = e
|
|
||||||
db.mu.Unlock()
|
|
||||||
return e, nil
|
return e, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *EraDatabase) Close() {
|
func (db *EraDatabase) Close() {
|
||||||
db.mu.Lock()
|
// Close all open era1 files in the cache.
|
||||||
defer db.mu.Unlock()
|
keys := db.cache.Keys()
|
||||||
for _, e := range db.table {
|
for _, key := range keys {
|
||||||
if err := e.Close(); err != nil {
|
if e, ok := db.cache.Get(key); ok {
|
||||||
log.Warn("Failed to close era", "error", err)
|
e.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
db.table = nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *EraDatabase) GetBlockByNumber(number uint64) (*types.Block, error) {
|
func (db *EraDatabase) GetBlockByNumber(number uint64) (*types.Block, error) {
|
||||||
files, err := db.scan()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for _, file := range files {
|
|
||||||
_, err := db.openEra(path.Join(db.datadir, file))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lookup the table by epoch.
|
// Lookup the table by epoch.
|
||||||
epoch := number / uint64(era.MaxEra1Size)
|
epoch := number / uint64(era.MaxEra1Size)
|
||||||
db.mu.RLock()
|
// Check the cache first.
|
||||||
defer db.mu.RUnlock()
|
if e, ok := db.cache.Get(epoch); ok {
|
||||||
if e, ok := db.table[epoch]; ok {
|
fmt.Printf("Cache hit for epoch %d\n", epoch)
|
||||||
block, err := e.GetBlockByNumber(number)
|
return e.GetBlockByNumber(number)
|
||||||
if err == nil {
|
|
||||||
return block, nil
|
|
||||||
}
|
}
|
||||||
|
// file name scheme is <network>-<epoch>-<root>.
|
||||||
|
glob := fmt.Sprintf("%s-%05d-*.era1", db.network, epoch)
|
||||||
|
matches, err := filepath.Glob(filepath.Join(db.datadir, glob))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if len(matches) > 1 {
|
||||||
|
return nil, fmt.Errorf("multiple era1 files found for epoch %d", epoch)
|
||||||
|
}
|
||||||
|
if len(matches) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
filename := matches[0]
|
||||||
|
e, err := db.openEra(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Add the era to the cache.
|
||||||
|
db.cache.Add(epoch, e)
|
||||||
|
|
||||||
return nil, errors.New("block not found")
|
return e.GetBlockByNumber(number)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,16 +24,12 @@ import (
|
||||||
|
|
||||||
func TestEraDatabase_Scan(t *testing.T) {
|
func TestEraDatabase_Scan(t *testing.T) {
|
||||||
// Create the database
|
// Create the database
|
||||||
db, err := New("testdata")
|
db, err := New("testdata", "sepolia")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Scan for era files
|
|
||||||
files, err := db.scan()
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
t.Log(files)
|
|
||||||
block, err := db.GetBlockByNumber(15000)
|
block, err := db.GetBlockByNumber(15000)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, block, "block not found")
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
require.Equal(t, uint64(15000), block.NumberU64())
|
require.Equal(t, uint64(15000), block.NumberU64())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ package era
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
@ -151,7 +150,7 @@ func (e *Era) GetHeaderByNumber(num uint64) (*types.Header, error) {
|
||||||
// GetBlockByNumber returns the block for the given block number.
|
// GetBlockByNumber returns the block for the given block number.
|
||||||
func (e *Era) GetBlockByNumber(num uint64) (*types.Block, error) {
|
func (e *Era) GetBlockByNumber(num uint64) (*types.Block, error) {
|
||||||
if e.m.start > num || e.m.start+e.m.count <= num {
|
if e.m.start > num || e.m.start+e.m.count <= num {
|
||||||
return nil, errors.New("out-of-bounds")
|
return nil, fmt.Errorf("out-of-bounds: %d not in [%d, %d)", num, e.m.start, e.m.start+e.m.count)
|
||||||
}
|
}
|
||||||
off, err := e.readOffset(num)
|
off, err := e.readOffset(num)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue