node: new function OpenDatabaseWithOptions

This commit is contained in:
Felix Lange 2025-05-23 22:39:23 +02:00 committed by lightclient
parent 7b237608e9
commit f8653e4128
No known key found for this signature in database
GPG key ID: 657913021EF45A6A
5 changed files with 83 additions and 72 deletions

View file

@ -45,6 +45,7 @@ import (
"github.com/ethereum/go-ethereum/internal/era/eradl" "github.com/ethereum/go-ethereum/internal/era/eradl"
"github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
@ -277,10 +278,7 @@ func initGenesis(ctx *cli.Context) error {
overrides.OverrideVerkle = &v overrides.OverrideVerkle = &v
} }
chaindb, err := stack.OpenDatabaseWithFreezer("chaindata", 0, 0, ctx.String(utils.AncientFlag.Name), "", false, "") chaindb := utils.MakeChainDatabase(ctx, stack, false)
if err != nil {
utils.Fatalf("Failed to open database: %v", err)
}
defer chaindb.Close() defer chaindb.Close()
triedb := utils.MakeTrieDatabase(ctx, chaindb, ctx.Bool(utils.CachePreimagesFlag.Name), false, genesis.IsVerkle()) triedb := utils.MakeTrieDatabase(ctx, chaindb, ctx.Bool(utils.CachePreimagesFlag.Name), false, genesis.IsVerkle())
@ -317,7 +315,7 @@ func dumpGenesis(ctx *cli.Context) error {
// dump whatever already exists in the datadir // dump whatever already exists in the datadir
stack, _ := makeConfigNode(ctx) stack, _ := makeConfigNode(ctx)
db, err := stack.OpenDatabase("chaindata", 0, 0, "", true) db, err := stack.OpenDatabaseWithOptions("chaindata", node.DatabaseOptions{ReadOnly: true})
if err != nil { if err != nil {
return err return err
} }

View file

@ -2081,7 +2081,15 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb.
} }
chainDb = remotedb.New(client) chainDb = remotedb.New(client)
default: default:
chainDb, err = stack.OpenDatabaseWithFreezer("chaindata", cache, handles, ctx.String(AncientFlag.Name), "eth/db/chaindata/", readonly, ctx.String(EraFlag.Name)) options := node.DatabaseOptions{
ReadOnly: readonly,
Cache: cache,
Handles: handles,
AncientsDirectory: ctx.String(AncientFlag.Name),
MetricsNamespace: "eth/db/chaindata/",
EraDirectory: ctx.String(EraFlag.Name),
}
chainDb, err = stack.OpenDatabaseWithOptions("chaindata", options)
} }
if err != nil { if err != nil {
Fatalf("Could not open database: %v", err) Fatalf("Could not open database: %v", err)

View file

@ -128,7 +128,14 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
} }
log.Info("Allocated trie memory caches", "clean", common.StorageSize(config.TrieCleanCache)*1024*1024, "dirty", common.StorageSize(config.TrieDirtyCache)*1024*1024) log.Info("Allocated trie memory caches", "clean", common.StorageSize(config.TrieCleanCache)*1024*1024, "dirty", common.StorageSize(config.TrieDirtyCache)*1024*1024)
chainDb, err := stack.OpenDatabaseWithFreezer("chaindata", config.DatabaseCache, config.DatabaseHandles, config.DatabaseFreezer, "eth/db/chaindata/", false, config.DatabaseEra) dbOptions := node.DatabaseOptions{
Cache: config.DatabaseCache,
Handles: config.DatabaseHandles,
AncientsDirectory: config.DatabaseFreezer,
EraDirectory: config.DatabaseEra,
MetricsNamespace: "eth/db/chaindata/",
}
chainDb, err := stack.OpenDatabaseWithOptions("chaindata", dbOptions)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -26,20 +26,25 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
// openOptions contains the options to apply when opening a database. // DatabaseOptions contains the options to apply when opening a database.
// OBS: If AncientsDirectory is empty, it indicates that no freezer is to be used. type DatabaseOptions struct {
type openOptions struct { // Directory for storing chain history ("freezer").
Type string // "leveldb" | "pebble" AncientsDirectory string
Directory string // the datadir
AncientsDirectory string // the ancients-dir
// The optional Era folder, which can be either a subfolder under // The optional Era folder, which can be either a subfolder under
// ancient/chain or a directory specified via an absolute path. // ancient/chain or a directory specified via an absolute path.
EraDirectory string EraDirectory string
Namespace string // the namespace for database relevant metrics
MetricsNamespace string // the namespace for database relevant metrics
Cache int // the capacity(in megabytes) of the data caching Cache int // the capacity(in megabytes) of the data caching
Handles int // number of files to be open simultaneously Handles int // number of files to be open simultaneously
ReadOnly bool ReadOnly bool // if true, no writes can be performed
}
type internalOpenOptions struct {
directory string
dbEngine string // "leveldb" | "pebble"
DatabaseOptions
} }
// openDatabase opens both a disk-based key-value database such as leveldb or pebble, but also // openDatabase opens both a disk-based key-value database such as leveldb or pebble, but also
@ -47,7 +52,7 @@ type openOptions struct {
// set on the provided OpenOptions. // set on the provided OpenOptions.
// The passed o.AncientDir indicates the path of root ancient directory where // The passed o.AncientDir indicates the path of root ancient directory where
// the chain freezer can be opened. // the chain freezer can be opened.
func openDatabase(o openOptions) (ethdb.Database, error) { func openDatabase(o internalOpenOptions) (ethdb.Database, error) {
kvdb, err := openKeyValueDatabase(o) kvdb, err := openKeyValueDatabase(o)
if err != nil { if err != nil {
return nil, err return nil, err
@ -58,7 +63,7 @@ func openDatabase(o openOptions) (ethdb.Database, error) {
opts := rawdb.OpenOptions{ opts := rawdb.OpenOptions{
Ancient: o.AncientsDirectory, Ancient: o.AncientsDirectory,
Era: o.EraDirectory, Era: o.EraDirectory,
MetricsNamespace: o.Namespace, MetricsNamespace: o.MetricsNamespace,
ReadOnly: o.ReadOnly, ReadOnly: o.ReadOnly,
} }
frdb, err := rawdb.Open(kvdb, opts) frdb, err := rawdb.Open(kvdb, opts)
@ -75,28 +80,28 @@ func openDatabase(o openOptions) (ethdb.Database, error) {
// +---------------------------------------- // +----------------------------------------
// db is non-existent | pebble default | specified type // db is non-existent | pebble default | specified type
// db is existent | from db | specified type (if compatible) // db is existent | from db | specified type (if compatible)
func openKeyValueDatabase(o openOptions) (ethdb.Database, error) { func openKeyValueDatabase(o internalOpenOptions) (ethdb.Database, error) {
// Reject any unsupported database type // Reject any unsupported database type
if len(o.Type) != 0 && o.Type != rawdb.DBLeveldb && o.Type != rawdb.DBPebble { if len(o.dbEngine) != 0 && o.dbEngine != rawdb.DBLeveldb && o.dbEngine != rawdb.DBPebble {
return nil, fmt.Errorf("unknown db.engine %v", o.Type) return nil, fmt.Errorf("unknown db.engine %v", o.dbEngine)
} }
// Retrieve any pre-existing database's type and use that or the requested one // Retrieve any pre-existing database's type and use that or the requested one
// as long as there's no conflict between the two types // as long as there's no conflict between the two types
existingDb := rawdb.PreexistingDatabase(o.Directory) existingDb := rawdb.PreexistingDatabase(o.directory)
if len(existingDb) != 0 && len(o.Type) != 0 && o.Type != existingDb { if len(existingDb) != 0 && len(o.dbEngine) != 0 && o.dbEngine != existingDb {
return nil, fmt.Errorf("db.engine choice was %v but found pre-existing %v database in specified data directory", o.Type, existingDb) return nil, fmt.Errorf("db.engine choice was %v but found pre-existing %v database in specified data directory", o.dbEngine, existingDb)
} }
if o.Type == rawdb.DBPebble || existingDb == rawdb.DBPebble { if o.dbEngine == rawdb.DBPebble || existingDb == rawdb.DBPebble {
log.Info("Using pebble as the backing database") log.Info("Using pebble as the backing database")
return newPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly) return newPebbleDBDatabase(o.directory, o.Cache, o.Handles, o.MetricsNamespace, o.ReadOnly)
} }
if o.Type == rawdb.DBLeveldb || existingDb == rawdb.DBLeveldb { if o.dbEngine == rawdb.DBLeveldb || existingDb == rawdb.DBLeveldb {
log.Info("Using leveldb as the backing database") log.Info("Using leveldb as the backing database")
return newLevelDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly) return newLevelDBDatabase(o.directory, o.Cache, o.Handles, o.MetricsNamespace, o.ReadOnly)
} }
// No pre-existing database, no user-requested one either. Default to Pebble. // No pre-existing database, no user-requested one either. Default to Pebble.
log.Info("Defaulting to pebble as the backing database") log.Info("Defaulting to pebble as the backing database")
return newPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly) return newPebbleDBDatabase(o.directory, o.Cache, o.Handles, o.MetricsNamespace, o.ReadOnly)
} }
// newLevelDBDatabase creates a persistent key-value database without a freezer // newLevelDBDatabase creates a persistent key-value database without a freezer

View file

@ -697,27 +697,26 @@ func (n *Node) EventMux() *event.TypeMux {
} }
// OpenDatabase opens an existing database with the given name (or creates one if no // OpenDatabase opens an existing database with the given name (or creates one if no
// previous can be found) from within the node's instance directory. If the node is // previous can be found) from within the node's instance directory. If the node has no
// ephemeral, a memory database is returned. // data directory, an in-memory database is returned.
func (n *Node) OpenDatabase(name string, cache, handles int, namespace string, readonly bool) (ethdb.Database, error) { func (n *Node) OpenDatabaseWithOptions(name string, opt DatabaseOptions) (ethdb.Database, error) {
n.lock.Lock() n.lock.Lock()
defer n.lock.Unlock() defer n.lock.Unlock()
if n.state == closedState { if n.state == closedState {
return nil, ErrNodeStopped return nil, ErrNodeStopped
} }
var db ethdb.Database var db ethdb.Database
var err error var err error
if n.config.DataDir == "" { if n.config.DataDir == "" {
db = rawdb.NewMemoryDatabase() db, _ = rawdb.Open(memorydb.New(), rawdb.OpenOptions{
MetricsNamespace: opt.MetricsNamespace,
ReadOnly: opt.ReadOnly,
})
} else { } else {
db, err = openDatabase(openOptions{ db, err = openDatabase(internalOpenOptions{
Type: n.config.DBEngine, directory: n.ResolvePath(name),
Directory: n.ResolvePath(name), dbEngine: n.config.DBEngine,
Namespace: namespace, DatabaseOptions: opt,
Cache: cache,
Handles: handles,
ReadOnly: readonly,
}) })
} }
if err == nil { if err == nil {
@ -726,37 +725,31 @@ func (n *Node) OpenDatabase(name string, cache, handles int, namespace string, r
return db, err return db, err
} }
// OpenDatabaseWithFreezer opens an existing database with the given name (or // OpenDatabase opens an existing database with the given name (or creates one if no
// creates one if no previous can be found) from within the node's data directory, // previous can be found) from within the node's instance directory.
// also attaching a chain freezer to it that moves ancient chain data from the // If the node has no data directory, an in-memory database is returned.
// database to immutable append-only files. If the node is an ephemeral one, a // Deprecated: use OpenDatabaseWithOptions instead.
// memory database is returned. func (n *Node) OpenDatabase(name string, cache, handles int, namespace string, readonly bool) (ethdb.Database, error) {
func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, ancient string, namespace string, readonly bool, era string) (ethdb.Database, error) { return n.OpenDatabaseWithOptions(name, DatabaseOptions{
n.lock.Lock() MetricsNamespace: namespace,
defer n.lock.Unlock() Cache: cache,
if n.state == closedState { Handles: handles,
return nil, ErrNodeStopped ReadOnly: readonly,
} })
var db ethdb.Database }
var err error
if n.config.DataDir == "" { // OpenDatabaseWithFreezer opens an existing database with the given name (or
db, err = rawdb.Open(memorydb.New(), rawdb.OpenOptions{MetricsNamespace: namespace, ReadOnly: readonly}) // creates one if no previous can be found) from within the node's data directory.
} else { // If the node has no data directory, an in-memory database is returned.
db, err = openDatabase(openOptions{ // Deprecated: use OpenDatabaseWithOptions instead.
Type: n.config.DBEngine, func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, ancient string, namespace string, readonly bool) (ethdb.Database, error) {
Directory: n.ResolvePath(name), return n.OpenDatabaseWithOptions(name, DatabaseOptions{
AncientsDirectory: n.ResolveAncient(name, ancient), AncientsDirectory: n.ResolveAncient(name, ancient),
EraDirectory: era, MetricsNamespace: namespace,
Namespace: namespace,
Cache: cache, Cache: cache,
Handles: handles, Handles: handles,
ReadOnly: readonly, ReadOnly: readonly,
}) })
}
if err == nil {
db = n.wrapDatabase(db)
}
return db, err
} }
// ResolvePath returns the absolute path of a resource in the instance directory. // ResolvePath returns the absolute path of a resource in the instance directory.