channeldb/db: adds optional dry-run abort for migrations
This commit is contained in:
parent
f3a427724b
commit
c775819372
@ -25,6 +25,12 @@ const (
|
|||||||
dbFilePermission = 0600
|
dbFilePermission = 0600
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrDryRunMigrationOK signals that a migration executed successful,
|
||||||
|
// but we intentionally did not commit the result.
|
||||||
|
ErrDryRunMigrationOK = errors.New("Dry run migration successful")
|
||||||
|
)
|
||||||
|
|
||||||
// migration is a function which takes a prior outdated version of the database
|
// migration is a function which takes a prior outdated version of the database
|
||||||
// instances and mutates the key/bucket structure to arrive at a more
|
// instances and mutates the key/bucket structure to arrive at a more
|
||||||
// up-to-date version of the database.
|
// up-to-date version of the database.
|
||||||
@ -145,6 +151,7 @@ type DB struct {
|
|||||||
dbPath string
|
dbPath string
|
||||||
graph *ChannelGraph
|
graph *ChannelGraph
|
||||||
clock clock.Clock
|
clock clock.Clock
|
||||||
|
dryRun bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open opens an existing channeldb. Any necessary schemas migrations due to
|
// Open opens an existing channeldb. Any necessary schemas migrations due to
|
||||||
@ -174,6 +181,7 @@ func Open(dbPath string, modifiers ...OptionModifier) (*DB, error) {
|
|||||||
Backend: bdb,
|
Backend: bdb,
|
||||||
dbPath: dbPath,
|
dbPath: dbPath,
|
||||||
clock: opts.clock,
|
clock: opts.clock,
|
||||||
|
dryRun: opts.dryRun,
|
||||||
}
|
}
|
||||||
chanDB.graph = newChannelGraph(
|
chanDB.graph = newChannelGraph(
|
||||||
chanDB, opts.RejectCacheSize, opts.ChannelCacheSize,
|
chanDB, opts.RejectCacheSize, opts.ChannelCacheSize,
|
||||||
@ -1227,7 +1235,18 @@ func (d *DB) syncVersions(versions []version) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
meta.DbVersionNumber = latestVersion
|
meta.DbVersionNumber = latestVersion
|
||||||
return putMeta(meta, tx)
|
err := putMeta(meta, tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// In dry-run mode, return an error to prevent the transaction
|
||||||
|
// from committing.
|
||||||
|
if d.dryRun {
|
||||||
|
return ErrDryRunMigrationOK
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +45,16 @@ func TestOpenWithCreate(t *testing.T) {
|
|||||||
if !fileExists(dbPath) {
|
if !fileExists(dbPath) {
|
||||||
t.Fatalf("channeldb failed to create data directory")
|
t.Fatalf("channeldb failed to create data directory")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now, reopen the same db in dry run migration mode. Since we have not
|
||||||
|
// applied any migrations, this should ignore the flag and not fail.
|
||||||
|
cdb, err = Open(dbPath, OptionDryRunMigration(true))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create channeldb: %v", err)
|
||||||
|
}
|
||||||
|
if err := cdb.Close(); err != nil {
|
||||||
|
t.Fatalf("unable to close channeldb: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestWipe tests that the database wipe operation completes successfully
|
// TestWipe tests that the database wipe operation completes successfully
|
||||||
|
@ -12,13 +12,14 @@ import (
|
|||||||
// applyMigration is a helper test function that encapsulates the general steps
|
// applyMigration is a helper test function that encapsulates the general steps
|
||||||
// which are needed to properly check the result of applying migration function.
|
// which are needed to properly check the result of applying migration function.
|
||||||
func applyMigration(t *testing.T, beforeMigration, afterMigration func(d *DB),
|
func applyMigration(t *testing.T, beforeMigration, afterMigration func(d *DB),
|
||||||
migrationFunc migration, shouldFail bool) {
|
migrationFunc migration, shouldFail bool, dryRun bool) {
|
||||||
|
|
||||||
cdb, cleanUp, err := makeTestDB()
|
cdb, cleanUp, err := makeTestDB()
|
||||||
defer cleanUp()
|
defer cleanUp()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
cdb.dryRun = dryRun
|
||||||
|
|
||||||
// Create a test node that will be our source node.
|
// Create a test node that will be our source node.
|
||||||
testNode, err := createTestVertex(cdb)
|
testNode, err := createTestVertex(cdb)
|
||||||
@ -54,6 +55,9 @@ func applyMigration(t *testing.T, beforeMigration, afterMigration func(d *DB),
|
|||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
|
if dryRun && r != ErrDryRunMigrationOK {
|
||||||
|
t.Fatalf("expected dry run migration OK")
|
||||||
|
}
|
||||||
err = errors.New(r)
|
err = errors.New(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,7 +260,8 @@ func TestMigrationWithPanic(t *testing.T) {
|
|||||||
beforeMigrationFunc,
|
beforeMigrationFunc,
|
||||||
afterMigrationFunc,
|
afterMigrationFunc,
|
||||||
migrationWithPanic,
|
migrationWithPanic,
|
||||||
true)
|
true,
|
||||||
|
false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestMigrationWithFatal asserts that migrations which fail do not modify the
|
// TestMigrationWithFatal asserts that migrations which fail do not modify the
|
||||||
@ -330,7 +335,8 @@ func TestMigrationWithFatal(t *testing.T) {
|
|||||||
beforeMigrationFunc,
|
beforeMigrationFunc,
|
||||||
afterMigrationFunc,
|
afterMigrationFunc,
|
||||||
migrationWithFatal,
|
migrationWithFatal,
|
||||||
true)
|
true,
|
||||||
|
false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestMigrationWithoutErrors asserts that a successful migration has its
|
// TestMigrationWithoutErrors asserts that a successful migration has its
|
||||||
@ -404,6 +410,7 @@ func TestMigrationWithoutErrors(t *testing.T) {
|
|||||||
beforeMigrationFunc,
|
beforeMigrationFunc,
|
||||||
afterMigrationFunc,
|
afterMigrationFunc,
|
||||||
migrationWithoutErrors,
|
migrationWithoutErrors,
|
||||||
|
false,
|
||||||
false)
|
false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,3 +453,38 @@ func TestMigrationReversion(t *testing.T) {
|
|||||||
"want: %v, got: %v", ErrDBReversion, err)
|
"want: %v, got: %v", ErrDBReversion, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestMigrationDryRun ensures that opening the database in dry run migration
|
||||||
|
// mode will fail and not commit the migration.
|
||||||
|
func TestMigrationDryRun(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// Nothing to do, will inspect version number.
|
||||||
|
beforeMigrationFunc := func(d *DB) {}
|
||||||
|
|
||||||
|
// Check that version of database version is not modified.
|
||||||
|
afterMigrationFunc := func(d *DB) {
|
||||||
|
err := kvdb.View(d, func(tx kvdb.ReadTx) error {
|
||||||
|
meta, err := d.FetchMeta(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if meta.DbVersionNumber != 0 {
|
||||||
|
t.Fatal("dry run migration was not aborted")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to apply after func: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
applyMigration(t,
|
||||||
|
beforeMigrationFunc,
|
||||||
|
afterMigrationFunc,
|
||||||
|
func(kvdb.RwTx) error { return nil },
|
||||||
|
true,
|
||||||
|
true)
|
||||||
|
}
|
||||||
|
@ -31,6 +31,10 @@ type Options struct {
|
|||||||
|
|
||||||
// clock is the time source used by the database.
|
// clock is the time source used by the database.
|
||||||
clock clock.Clock
|
clock clock.Clock
|
||||||
|
|
||||||
|
// dryRun will fail to commit a successful migration when opening the
|
||||||
|
// database if set to true.
|
||||||
|
dryRun bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultOptions returns an Options populated with default values.
|
// DefaultOptions returns an Options populated with default values.
|
||||||
@ -73,3 +77,11 @@ func OptionClock(clock clock.Clock) OptionModifier {
|
|||||||
o.clock = clock
|
o.clock = clock
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OptionDryRunMigration controls whether or not to intentially fail to commit a
|
||||||
|
// successful migration that occurs when opening the database.
|
||||||
|
func OptionDryRunMigration(dryRun bool) OptionModifier {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.dryRun = dryRun
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user