From d3ece3a07ca5617476f11e909904c847bc096714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 21 Apr 2023 19:24:18 +0300 Subject: [PATCH] cmd/utils, node: switch to Pebble as the default db if none exists (#27136) * cmd/utils, node: switch to Pebble as the default db if none exists * node: fall back to LevelDB on platforms not supporting Pebble * core/rawdb, node: default to Pebble at the node level * cmd/geth: fix some tests explicitly using leveldb * ethdb/pebble: allow double closes, makes tests simpler --- cmd/geth/dao_test.go | 2 +- cmd/geth/genesis_test.go | 4 ++-- cmd/utils/flags.go | 4 ++-- core/rawdb/database.go | 27 ++++++++++++++++++++------- ethdb/pebble/pebble.go | 17 ++++++++++------- node/defaults.go | 16 +++++++--------- 6 files changed, 42 insertions(+), 28 deletions(-) diff --git a/cmd/geth/dao_test.go b/cmd/geth/dao_test.go index 0701a2d5a..5af78116f 100644 --- a/cmd/geth/dao_test.go +++ b/cmd/geth/dao_test.go @@ -121,7 +121,7 @@ func testDAOForkBlockNewChain(t *testing.T, test int, genesis string, expectBloc } // Retrieve the DAO config flag from the database path := filepath.Join(datadir, "geth", "chaindata") - db, err := rawdb.NewLevelDBDatabase(path, 0, 0, "", false) + db, err := rawdb.NewPebbleDBDatabase(path, 0, 0, "", false) if err != nil { t.Fatalf("test %d: failed to open test database: %v", test, err) } diff --git a/cmd/geth/genesis_test.go b/cmd/geth/genesis_test.go index 8e379b867..d88346c93 100644 --- a/cmd/geth/genesis_test.go +++ b/cmd/geth/genesis_test.go @@ -146,8 +146,8 @@ func TestCustomBackend(t *testing.T) { return nil } for i, tt := range []backendTest{ - { // When not specified, it should default to leveldb - execArgs: []string{"--db.engine", "leveldb"}, + { // When not specified, it should default to pebble + execArgs: []string{"--db.engine", "pebble"}, execExpect: "0x0000000000001338", }, { // Explicit leveldb diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 08de71ee8..e9b6320ad 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -101,8 +101,8 @@ var ( } DBEngineFlag = &cli.StringFlag{ Name: "db.engine", - Usage: "Backing database implementation to use ('leveldb' or 'pebble')", - Value: "leveldb", + Usage: "Backing database implementation to use ('pebble' or 'leveldb')", + Value: node.DefaultConfig.DBEngine, Category: flags.EthCategory, } AncientFlag = &flags.DirectoryFlag{ diff --git a/core/rawdb/database.go b/core/rawdb/database.go index b8cc36a81..e864bcb2e 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -358,9 +358,15 @@ type OpenOptions struct { // // type == null type != null // +---------------------------------------- -// db is non-existent | leveldb default | specified type -// db is existent | from db | specified type (if compatible) +// db is non-existent | pebble default | specified type +// db is existent | from db | specified type (if compatible) func openKeyValueDatabase(o OpenOptions) (ethdb.Database, error) { + // Reject any unsupported database type + if len(o.Type) != 0 && o.Type != dbLeveldb && o.Type != dbPebble { + return nil, fmt.Errorf("unknown db.engine %v", o.Type) + } + // 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 := hasPreexistingDb(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) @@ -373,12 +379,19 @@ func openKeyValueDatabase(o OpenOptions) (ethdb.Database, error) { return nil, errors.New("db.engine 'pebble' not supported on this platform") } } - if len(o.Type) != 0 && o.Type != dbLeveldb { - return nil, fmt.Errorf("unknown db.engine %v", o.Type) + if o.Type == dbLeveldb || existingDb == dbLeveldb { + log.Info("Using leveldb as the backing database") + return NewLevelDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly) + } + // No pre-existing database, no user-requested one either. Default to Pebble + // on supported platforms and LevelDB on anything else. + if PebbleEnabled { + log.Info("Defaulting to pebble as the backing database") + return NewPebbleDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly) + } else { + log.Info("Defaulting to leveldb as the backing database") + return NewLevelDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly) } - log.Info("Using leveldb as the backing database") - // Use leveldb, either as default (no explicit choice), or pre-existing, or chosen explicitly - return NewLevelDBDatabase(o.Directory, o.Cache, o.Handles, o.Namespace, o.ReadOnly) } // Open opens both a disk-based key-value database such as leveldb or pebble, but also diff --git a/ethdb/pebble/pebble.go b/ethdb/pebble/pebble.go index 7c01b879b..5be4c1af7 100644 --- a/ethdb/pebble/pebble.go +++ b/ethdb/pebble/pebble.go @@ -222,14 +222,17 @@ func (d *Database) Close() error { d.quitLock.Lock() defer d.quitLock.Unlock() - if d.quitChan != nil { - errc := make(chan error) - d.quitChan <- errc - if err := <-errc; err != nil { - d.log.Error("Metrics collection failed", "err", err) - } - d.quitChan = nil + // Allow double closing, simplifies things + if d.quitChan == nil { + return nil } + errc := make(chan error) + d.quitChan <- errc + if err := <-errc; err != nil { + d.log.Error("Metrics collection failed", "err", err) + } + d.quitChan = nil + return d.db.Close() } diff --git a/node/defaults.go b/node/defaults.go index 96ebed81c..fcfbc934b 100644 --- a/node/defaults.go +++ b/node/defaults.go @@ -28,14 +28,12 @@ import ( ) const ( - DefaultHTTPHost = "localhost" // Default host interface for the HTTP RPC server - DefaultHTTPPort = 8545 // Default TCP port for the HTTP RPC server - DefaultWSHost = "localhost" // Default host interface for the websocket RPC server - DefaultWSPort = 8546 // Default TCP port for the websocket RPC server - DefaultGraphQLHost = "localhost" // Default host interface for the GraphQL server - DefaultGraphQLPort = 8547 // Default TCP port for the GraphQL server - DefaultAuthHost = "localhost" // Default host interface for the authenticated apis - DefaultAuthPort = 8551 // Default port for the authenticated apis + DefaultHTTPHost = "localhost" // Default host interface for the HTTP RPC server + DefaultHTTPPort = 8545 // Default TCP port for the HTTP RPC server + DefaultWSHost = "localhost" // Default host interface for the websocket RPC server + DefaultWSPort = 8546 // Default TCP port for the websocket RPC server + DefaultAuthHost = "localhost" // Default host interface for the authenticated apis + DefaultAuthPort = 8551 // Default port for the authenticated apis ) var ( @@ -64,7 +62,7 @@ var DefaultConfig = Config{ MaxPeers: 50, NAT: nat.Any(), }, - DBEngine: "", + DBEngine: "", // Use whatever exists, will default to Pebble if non-existent and supported } // DefaultDataDir is the default data directory to use for the databases and other