From f8653e412895b22c9ae5ea67d292cc88ea408fda Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Fri, 23 May 2025 22:39:23 +0200 Subject: [PATCH] node: new function OpenDatabaseWithOptions --- cmd/geth/chaincmd.go | 8 ++--- cmd/utils/flags.go | 10 +++++- eth/backend.go | 9 +++++- node/database.go | 51 ++++++++++++++++------------- node/node.go | 77 ++++++++++++++++++++------------------------ 5 files changed, 83 insertions(+), 72 deletions(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index f776bd3271..d8488b8268 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -45,6 +45,7 @@ import ( "github.com/ethereum/go-ethereum/internal/era/eradl" "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/params" "github.com/urfave/cli/v2" ) @@ -277,10 +278,7 @@ func initGenesis(ctx *cli.Context) error { overrides.OverrideVerkle = &v } - chaindb, err := stack.OpenDatabaseWithFreezer("chaindata", 0, 0, ctx.String(utils.AncientFlag.Name), "", false, "") - if err != nil { - utils.Fatalf("Failed to open database: %v", err) - } + chaindb := utils.MakeChainDatabase(ctx, stack, false) defer chaindb.Close() 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 stack, _ := makeConfigNode(ctx) - db, err := stack.OpenDatabase("chaindata", 0, 0, "", true) + db, err := stack.OpenDatabaseWithOptions("chaindata", node.DatabaseOptions{ReadOnly: true}) if err != nil { return err } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 2c675337e1..9d5a1763f3 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -2081,7 +2081,15 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb. } chainDb = remotedb.New(client) 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 { Fatalf("Could not open database: %v", err) diff --git a/eth/backend.go b/eth/backend.go index 0d294a7232..ba087c5843 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -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) - 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 { return nil, err } diff --git a/node/database.go b/node/database.go index 63b2cf9621..65f96c9f91 100644 --- a/node/database.go +++ b/node/database.go @@ -26,20 +26,25 @@ import ( "github.com/ethereum/go-ethereum/log" ) -// openOptions contains the options to apply when opening a database. -// OBS: If AncientsDirectory is empty, it indicates that no freezer is to be used. -type openOptions struct { - Type string // "leveldb" | "pebble" - Directory string // the datadir - AncientsDirectory string // the ancients-dir +// DatabaseOptions contains the options to apply when opening a database. +type DatabaseOptions struct { + // Directory for storing chain history ("freezer"). + AncientsDirectory string // The optional Era folder, which can be either a subfolder under // ancient/chain or a directory specified via an absolute path. EraDirectory string - Namespace string // the namespace for database relevant metrics - Cache int // the capacity(in megabytes) of the data caching - Handles int // number of files to be open simultaneously - ReadOnly bool + + MetricsNamespace string // the namespace for database relevant metrics + Cache int // the capacity(in megabytes) of the data caching + Handles int // number of files to be open simultaneously + 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 @@ -47,7 +52,7 @@ type openOptions struct { // set on the provided OpenOptions. // The passed o.AncientDir indicates the path of root ancient directory where // the chain freezer can be opened. -func openDatabase(o openOptions) (ethdb.Database, error) { +func openDatabase(o internalOpenOptions) (ethdb.Database, error) { kvdb, err := openKeyValueDatabase(o) if err != nil { return nil, err @@ -58,7 +63,7 @@ func openDatabase(o openOptions) (ethdb.Database, error) { opts := rawdb.OpenOptions{ Ancient: o.AncientsDirectory, Era: o.EraDirectory, - MetricsNamespace: o.Namespace, + MetricsNamespace: o.MetricsNamespace, ReadOnly: o.ReadOnly, } 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 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 - if len(o.Type) != 0 && o.Type != rawdb.DBLeveldb && o.Type != rawdb.DBPebble { - return nil, fmt.Errorf("unknown db.engine %v", o.Type) + if len(o.dbEngine) != 0 && o.dbEngine != rawdb.DBLeveldb && o.dbEngine != rawdb.DBPebble { + return nil, fmt.Errorf("unknown db.engine %v", o.dbEngine) } // 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 - existingDb := rawdb.PreexistingDatabase(o.Directory) - if len(existingDb) != 0 && len(o.Type) != 0 && o.Type != existingDb { - return nil, fmt.Errorf("db.engine choice was %v but found pre-existing %v database in specified data directory", o.Type, existingDb) + existingDb := rawdb.PreexistingDatabase(o.directory) + 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.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") - 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") - 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. 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 diff --git a/node/node.go b/node/node.go index 8114182f04..b42f9ef6c1 100644 --- a/node/node.go +++ b/node/node.go @@ -697,27 +697,26 @@ func (n *Node) EventMux() *event.TypeMux { } // 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 -// ephemeral, a memory database is returned. -func (n *Node) OpenDatabase(name string, cache, handles int, namespace string, readonly bool) (ethdb.Database, error) { +// previous can be found) from within the node's instance directory. If the node has no +// data directory, an in-memory database is returned. +func (n *Node) OpenDatabaseWithOptions(name string, opt DatabaseOptions) (ethdb.Database, error) { n.lock.Lock() defer n.lock.Unlock() if n.state == closedState { return nil, ErrNodeStopped } - var db ethdb.Database var err error if n.config.DataDir == "" { - db = rawdb.NewMemoryDatabase() + db, _ = rawdb.Open(memorydb.New(), rawdb.OpenOptions{ + MetricsNamespace: opt.MetricsNamespace, + ReadOnly: opt.ReadOnly, + }) } else { - db, err = openDatabase(openOptions{ - Type: n.config.DBEngine, - Directory: n.ResolvePath(name), - Namespace: namespace, - Cache: cache, - Handles: handles, - ReadOnly: readonly, + db, err = openDatabase(internalOpenOptions{ + directory: n.ResolvePath(name), + dbEngine: n.config.DBEngine, + DatabaseOptions: opt, }) } if err == nil { @@ -726,37 +725,31 @@ func (n *Node) OpenDatabase(name string, cache, handles int, namespace string, r return db, err } +// 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 has no data directory, an in-memory database is returned. +// Deprecated: use OpenDatabaseWithOptions instead. +func (n *Node) OpenDatabase(name string, cache, handles int, namespace string, readonly bool) (ethdb.Database, error) { + return n.OpenDatabaseWithOptions(name, DatabaseOptions{ + MetricsNamespace: namespace, + Cache: cache, + Handles: handles, + ReadOnly: readonly, + }) +} + // OpenDatabaseWithFreezer opens an existing database with the given name (or -// creates one if no previous can be found) from within the node's data directory, -// also attaching a chain freezer to it that moves ancient chain data from the -// database to immutable append-only files. If the node is an ephemeral one, a -// memory database is returned. -func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, ancient string, namespace string, readonly bool, era string) (ethdb.Database, error) { - n.lock.Lock() - defer n.lock.Unlock() - if n.state == closedState { - return nil, ErrNodeStopped - } - var db ethdb.Database - var err error - if n.config.DataDir == "" { - db, err = rawdb.Open(memorydb.New(), rawdb.OpenOptions{MetricsNamespace: namespace, ReadOnly: readonly}) - } else { - db, err = openDatabase(openOptions{ - Type: n.config.DBEngine, - Directory: n.ResolvePath(name), - AncientsDirectory: n.ResolveAncient(name, ancient), - EraDirectory: era, - Namespace: namespace, - Cache: cache, - Handles: handles, - ReadOnly: readonly, - }) - } - if err == nil { - db = n.wrapDatabase(db) - } - return db, err +// creates one if no previous can be found) from within the node's data directory. +// If the node has no data directory, an in-memory database is returned. +// Deprecated: use OpenDatabaseWithOptions instead. +func (n *Node) OpenDatabaseWithFreezer(name string, cache, handles int, ancient string, namespace string, readonly bool) (ethdb.Database, error) { + return n.OpenDatabaseWithOptions(name, DatabaseOptions{ + AncientsDirectory: n.ResolveAncient(name, ancient), + MetricsNamespace: namespace, + Cache: cache, + Handles: handles, + ReadOnly: readonly, + }) } // ResolvePath returns the absolute path of a resource in the instance directory.