Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 31 additions & 6 deletions cmd_migrate_db.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ type migrateDBCommand struct {
ForceNewMigration bool `long:"force-new-migration" description:"Force a new migration from the beginning of the source DB so the resume state will be discarded"`
ForceVerifyDB bool `long:"force-verify-db" description:"Force a verification verifies two already marked (tombstoned and already migrated) dbs to make sure that the source db equals the content of the destination db"`
ChunkSize uint64 `long:"chunk-size" description:"Chunk size for the migration in bytes"`
ErrorIfNoBboltDB bool `long:"error-if-no-bbolt-db-exists" description:"Return an error when a mandatory source bbolt DB is not found. By default missing source DBs are logged and skipped so a fresh node (no bbolt DBs yet) is treated as a successful no-op."`
}

func newMigrateDBCommand() *migrateDBCommand {
Expand Down Expand Up @@ -232,13 +233,26 @@ func (x *migrateDBCommand) Execute(_ []string) error {
// Open and check the database version.
srcDb, err := openSourceDb(x.Source, prefix, x.Network, true)
if err == kvdb.ErrDbDoesNotExist {
// Only skip if it's an optional because it's not
// required to run a wtclient or wtserver for example.
if optionalDBs[prefix] {
switch {
// Optional DBs (e.g. wtclient, wtserver, neutrino) are
// always safe to skip when missing.
case optionalDBs[prefix]:
logger.Warnf("Skipping checking db version "+
"of optional DB %s: not found", prefix)

continue

// A mandatory bbolt DB is missing. Treat this as a
// fresh node by default (LND will create the SQL DB
// itself on first start). Only fail if the user
// explicitly opted in via --error-if-no-bbolt-db-exists.
case !x.ErrorIfNoBboltDB:
logger.Warnf("Skipping checking db version "+
"of mandatory DB %s: not found "+
"(pass --error-if-no-bbolt-db-exists "+
"to fail instead)", prefix)

continue
}
}
if err != nil {
Expand Down Expand Up @@ -281,12 +295,23 @@ func (x *migrateDBCommand) Execute(_ []string) error {
x.Source, prefix, x.Network, true,
)
if err == kvdb.ErrDbDoesNotExist {
// Only skip if it's an optional because it's not
// required to run a wtclient or wtserver for example.
if optionalDBs[prefix] {
switch {
// Optional DBs (e.g. wtclient, wtserver, neutrino) are
// always safe to skip when missing.
case optionalDBs[prefix]:
logger.Warnf("Skipping optional DB %s: not "+
"found", prefix)
continue

// A mandatory bbolt DB is missing. Treat this as a
// fresh node by default (LND will create the SQL DB
// itself on first start). Only fail if the user
// explicitly opted in via --error-if-no-bbolt-db-exists.
case !x.ErrorIfNoBboltDB:
logger.Warnf("Skipping mandatory DB %s: not "+
"found (pass --error-if-no-bbolt-db-"+
"exists to fail instead)", prefix)
continue
}
}
if err != nil {
Expand Down
54 changes: 54 additions & 0 deletions cmd_migrate_db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package main
import (
"testing"

"github.com/lightningnetwork/lnd/kvdb"
"github.com/lightningnetwork/lnd/kvdb/sqlite"
"github.com/lightningnetwork/lnd/lncfg"
"github.com/stretchr/testify/require"
)

Expand All @@ -20,3 +23,54 @@ func setupTestData(t *testing.T) string {

return tempDir
}

// TestMigrateDBNoBboltDBExists verifies that running migrate-db against a data
// directory that contains no bbolt source DBs is a successful no-op by default
// and only fails when --error-if-no-bbolt-db-exists is set.
func TestMigrateDBNoBboltDBExists(t *testing.T) {
t.Parallel()

makeCmd := func(dataDir string, errIfMissing bool) *migrateDBCommand {
return &migrateDBCommand{
Source: &SourceDB{
Backend: lncfg.BoltBackend,
Bolt: &Bolt{
DBTimeout: kvdb.DefaultDBTimeout,
DataDir: dataDir,
TowerDir: dataDir,
},
},
Dest: &DestDB{
Backend: lncfg.SqliteBackend,
Sqlite: &Sqlite{
DataDir: dataDir,
TowerDir: dataDir,
Config: &sqlite.Config{},
},
},
Network: "regtest",
ChunkSize: 1024,
ErrorIfNoBboltDB: errIfMissing,
}
}

t.Run("default skips missing DBs", func(t *testing.T) {
t.Parallel()

// An empty temp dir contains no bbolt DBs at all. With the
// default flag value the migration should succeed without
// touching the destination.
err := makeCmd(t.TempDir(), false).Execute(nil)
require.NoError(t, err)
})

t.Run("flag forces error when missing", func(t *testing.T) {
t.Parallel()

err := makeCmd(t.TempDir(), true).Execute(nil)
require.Error(t, err)
require.Contains(
t, err.Error(), "failed to open source db",
)
})
}
2 changes: 2 additions & 0 deletions docs/data-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,8 @@ Help Options:
--force-verify-db Force a verification verifies two already marked (tombstoned and already migrated) dbs to make sure that the source db equals the
content of the destination db
--chunk-size= Chunk size for the migration in bytes
--error-if-no-bbolt-db-exists Return an error when a mandatory source bbolt DB is not found. By default missing source DBs are logged and skipped so a fresh node (no bbolt
DBs yet) is treated as a successful no-op.

source:
--source.backend=[bolt] The source database backend. (default: bolt)
Expand Down