Skip to content

Commit

Permalink
Merge pull request #2447 from OffchainLabs/autodetect-db
Browse files Browse the repository at this point in the history
[config change] support auto-detection of database engine
  • Loading branch information
joshuacolvin0 authored Jul 1, 2024
2 parents 3767b1f + b0f2287 commit dc84707
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 6 deletions.
13 changes: 7 additions & 6 deletions cmd/conf/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ var PersistentConfigDefault = PersistentConfig{
LogDir: "",
Handles: 512,
Ancient: "",
DBEngine: "leveldb",
DBEngine: "", // auto-detect database type based on the db dir contents
Pebble: PebbleConfigDefault,
}

Expand All @@ -42,7 +42,7 @@ func PersistentConfigAddOptions(prefix string, f *flag.FlagSet) {
f.String(prefix+".log-dir", PersistentConfigDefault.LogDir, "directory to store log file")
f.Int(prefix+".handles", PersistentConfigDefault.Handles, "number of file descriptor handles to use for the database")
f.String(prefix+".ancient", PersistentConfigDefault.Ancient, "directory of ancient where the chain freezer can be opened")
f.String(prefix+".db-engine", PersistentConfigDefault.DBEngine, "backing database implementation to use ('leveldb' or 'pebble')")
f.String(prefix+".db-engine", PersistentConfigDefault.DBEngine, "backing database implementation to use. If set to empty string the database type will be autodetected and if no pre-existing database is found it will default to creating new pebble database ('leveldb', 'pebble' or '' = auto-detect)")
PebbleConfigAddOptions(prefix+".pebble", f)
}

Expand Down Expand Up @@ -97,11 +97,12 @@ func DatabaseInDirectory(path string) bool {
}

func (c *PersistentConfig) Validate() error {
// we are validating .db-engine here to avoid unintended behaviour as empty string value also has meaning in geth's node.Config.DBEngine
if c.DBEngine != "leveldb" && c.DBEngine != "pebble" {
return fmt.Errorf(`invalid .db-engine choice: %q, allowed "leveldb" or "pebble"`, c.DBEngine)
if c.DBEngine != "leveldb" && c.DBEngine != "pebble" && c.DBEngine != "" {
return fmt.Errorf(`invalid .db-engine choice: %q, allowed "leveldb", "pebble" or ""`, c.DBEngine)
}
if c.DBEngine == "pebble" {
// if DBEngine == "" then we may end up opening pebble database, so we want to validate the Pebble config
// if pre-existing database is leveldb backed, then user shouldn't change the Pebble config defaults => this check should also succeed
if c.DBEngine == "pebble" || c.DBEngine == "" {
if err := c.Pebble.Validate(); err != nil {
return err
}
Expand Down
14 changes: 14 additions & 0 deletions cmd/nitro/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"os"
"path"
"path/filepath"
"regexp"
"runtime"
"strings"
"sync"
Expand Down Expand Up @@ -326,6 +327,16 @@ func dirExists(path string) bool {
return info.IsDir()
}

var pebbleNotExistErrorRegex = regexp.MustCompile("pebble: database .* does not exist")

func isPebbleNotExistError(err error) bool {
return pebbleNotExistErrorRegex.MatchString(err.Error())
}

func isLeveldbNotExistError(err error) bool {
return os.IsNotExist(err)
}

func openInitializeChainDb(ctx context.Context, stack *node.Node, config *NodeConfig, chainId *big.Int, cacheConfig *core.CacheConfig, persistentConfig *conf.PersistentConfig, l1Client arbutil.L1Interface, rollupAddrs chaininfo.RollupAddresses) (ethdb.Database, *core.BlockChain, error) {
if !config.Init.Force {
if readOnlyDb, err := stack.OpenDatabaseWithFreezerWithExtraOptions("l2chaindata", 0, 0, "", "l2chaindata/", true, persistentConfig.Pebble.ExtraOptions("l2chaindata")); err == nil {
Expand Down Expand Up @@ -396,6 +407,9 @@ func openInitializeChainDb(ctx context.Context, stack *node.Node, config *NodeCo
return chainDb, l2BlockChain, nil
}
readOnlyDb.Close()
} else if !isLeveldbNotExistError(err) && !isPebbleNotExistError(err) {
// we only want to continue if the error is pebble or leveldb not exist error
return nil, nil, fmt.Errorf("Failed to open database: %w", err)
}
}

Expand Down
33 changes: 33 additions & 0 deletions cmd/nitro/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"testing"
"time"

"github.com/ethereum/go-ethereum/node"
"github.com/offchainlabs/nitro/cmd/conf"
"github.com/offchainlabs/nitro/util/testhelpers"
)
Expand Down Expand Up @@ -177,3 +178,35 @@ func startFileServer(t *testing.T, ctx context.Context, dir string) string {
}()
return addr
}

func testIsNotExistError(t *testing.T, dbEngine string, isNotExist func(error) bool) {
stackConf := node.DefaultConfig
stackConf.DataDir = t.TempDir()
stackConf.DBEngine = dbEngine
stack, err := node.New(&stackConf)
if err != nil {
t.Fatalf("Failed to created test stack: %v", err)
}
defer stack.Close()
readonly := true
_, err = stack.OpenDatabaseWithExtraOptions("test", 16, 16, "", readonly, nil)
if err == nil {
t.Fatal("Opening non-existent database did not fail")
}
if !isNotExist(err) {
t.Fatalf("Failed to classify error as not exist error - internal implementation of OpenDatabaseWithExtraOptions might have changed, err: %v", err)
}
err = errors.New("some other error")
if isNotExist(err) {
t.Fatalf("Classified other error as not exist, err: %v", err)
}
}

func TestIsNotExistError(t *testing.T) {
t.Run("TestIsPebbleNotExistError", func(t *testing.T) {
testIsNotExistError(t, "pebble", isPebbleNotExistError)
})
t.Run("TestIsLeveldbNotExistError", func(t *testing.T) {
testIsNotExistError(t, "leveldb", isLeveldbNotExistError)
})
}

0 comments on commit dc84707

Please sign in to comment.