lnd: run invoice migration on startup

This commit runs the invoice migration if the user has a KV SQL backend
configured.
This commit is contained in:
Andras Banki-Horvath 2024-09-17 15:18:12 +02:00
parent 94e2724a34
commit 8d20e2a23b
No known key found for this signature in database
GPG Key ID: 80E5375C094198D8
5 changed files with 71 additions and 41 deletions

View File

@ -51,6 +51,7 @@ import (
"github.com/lightningnetwork/lnd/rpcperms"
"github.com/lightningnetwork/lnd/signal"
"github.com/lightningnetwork/lnd/sqldb"
"github.com/lightningnetwork/lnd/sqldb/sqlc"
"github.com/lightningnetwork/lnd/sweep"
"github.com/lightningnetwork/lnd/walletunlocker"
"github.com/lightningnetwork/lnd/watchtower"
@ -60,6 +61,16 @@ import (
"gopkg.in/macaroon-bakery.v2/bakery"
)
const (
// invoiceMigrationBatchSize is the number of invoices that will be
// migrated in a single batch.
invoiceMigrationBatchSize = 1000
// invoiceMigration is the version of the migration that will be used to
// migrate invoices from the kvdb to the sql database.
invoiceMigration = 7
)
// GrpcRegistrar is an interface that must be satisfied by an external subserver
// that wants to be able to register its own gRPC server onto lnd's main
// grpc.Server instance.
@ -1038,7 +1049,7 @@ func (d *DefaultDatabaseBuilder) BuildDatabase(
if err != nil {
cleanUp()
err := fmt.Errorf("unable to open graph DB: %w", err)
err = fmt.Errorf("unable to open graph DB: %w", err)
d.logger.Error(err)
return nil, nil, err
@ -1072,65 +1083,69 @@ func (d *DefaultDatabaseBuilder) BuildDatabase(
case err != nil:
cleanUp()
err := fmt.Errorf("unable to open graph DB: %w", err)
err = fmt.Errorf("unable to open graph DB: %w", err)
d.logger.Error(err)
return nil, nil, err
}
// Instantiate a native SQL invoice store if the flag is set.
// Instantiate a native SQL store if the flag is set.
if d.cfg.DB.UseNativeSQL {
migrations := sqldb.GetMigrations()
// If the user has not explicitly disabled the SQL invoice
// migration, attach the custom migration function to invoice
// migration (version 7). Even if this custom migration is
// disabled, the regular native SQL store migrations will still
// run. If the database version is already above this custom
// migration's version (7), it will be skipped permanently,
// regardless of the flag.
if !d.cfg.DB.SkipSQLInvoiceMigration {
migrationFn := func(tx *sqlc.Queries) error {
return invoices.MigrateInvoicesToSQL(
ctx, dbs.ChanStateDB.Backend,
dbs.ChanStateDB, tx,
invoiceMigrationBatchSize,
)
}
// Make sure we attach the custom migration function to
// the correct migration version.
for i := 0; i < len(migrations); i++ {
if migrations[i].Version != invoiceMigration {
continue
}
migrations[i].MigrationFn = migrationFn
}
}
// We need to apply all migrations to the native SQL store
// before we can use it.
err := dbs.NativeSQLStore.ApplyAllMigrations(
ctx, sqldb.GetMigrations(),
)
err = dbs.NativeSQLStore.ApplyAllMigrations(ctx, migrations)
if err != nil {
cleanUp()
err := fmt.Errorf("unable to apply migrations: %w", err)
d.logger.Error(err)
return nil, nil, err
}
// KV invoice db resides in the same database as the channel
// state DB. Let's query the database to see if we have any
// invoices there. If we do, we won't allow the user to start
// lnd with native SQL enabled, as we don't currently migrate
// the invoices to the new database schema.
invoiceSlice, err := dbs.ChanStateDB.QueryInvoices(
ctx, invoices.InvoiceQuery{
NumMaxInvoices: 1,
},
)
if err != nil {
cleanUp()
d.logger.Errorf("Unable to query KV invoice DB: %v",
err)
return nil, nil, err
}
if len(invoiceSlice.Invoices) > 0 {
cleanUp()
err := fmt.Errorf("found invoices in the KV invoice " +
"DB, migration to native SQL is not yet " +
"supported")
err = fmt.Errorf("faild to run migrations for the "+
"native SQL store: %w", err)
d.logger.Error(err)
return nil, nil, err
}
// With the DB ready and migrations applied, we can now create
// the base DB and transaction executor for the native SQL
// invoice store.
baseDB := dbs.NativeSQLStore.GetBaseDB()
executor := sqldb.NewTransactionExecutor(
baseDB,
func(tx *sql.Tx) invoices.SQLInvoiceQueries {
baseDB, func(tx *sql.Tx) invoices.SQLInvoiceQueries {
return baseDB.WithTx(tx)
},
)
dbs.InvoiceDB = invoices.NewSQLStore(
sqlInvoiceDB := invoices.NewSQLStore(
executor, clock.NewDefaultClock(),
)
dbs.InvoiceDB = sqlInvoiceDB
} else {
dbs.InvoiceDB = dbs.ChanStateDB
}
@ -1143,7 +1158,7 @@ func (d *DefaultDatabaseBuilder) BuildDatabase(
if err != nil {
cleanUp()
err := fmt.Errorf("unable to open %s database: %w",
err = fmt.Errorf("unable to open %s database: %w",
lncfg.NSTowerClientDB, err)
d.logger.Error(err)
return nil, nil, err
@ -1158,7 +1173,7 @@ func (d *DefaultDatabaseBuilder) BuildDatabase(
if err != nil {
cleanUp()
err := fmt.Errorf("unable to open %s database: %w",
err = fmt.Errorf("unable to open %s database: %w",
lncfg.NSTowerServerDB, err)
d.logger.Error(err)
return nil, nil, err

Binary file not shown.

View File

@ -87,6 +87,8 @@ type DB struct {
UseNativeSQL bool `long:"use-native-sql" description:"Use native SQL for tables that already support it."`
SkipSQLInvoiceMigration bool `long:"skip-sql-invoice-migration" description:"Do not migrate invoices stored in our key-value database to native SQL."`
NoGraphCache bool `long:"no-graph-cache" description:"Don't use the in-memory graph cache for path finding. Much slower but uses less RAM. Can only be used with a bolt database backend."`
PruneRevocation bool `long:"prune-revocation" description:"Run the optional migration that prunes the revocation logs to save disk space."`
@ -116,6 +118,7 @@ func DefaultDB() *DB {
BusyTimeout: defaultSqliteBusyTimeout,
},
UseNativeSQL: false,
SkipSQLInvoiceMigration: false,
}
}

View File

@ -1472,6 +1472,9 @@
; own risk.
; db.use-native-sql=false
; If set to true, native SQL invoice migration will be skipped. Note that this
; option is intended for users who experience non-resolvable migration errors.
; db.skip-sql-invoice-migration=false
[etcd]

View File

@ -61,6 +61,15 @@ var (
Version: 6,
SchemaVersion: 6,
},
{
Name: "kv_invoice_migration",
Version: 7,
SchemaVersion: 6,
// A migration function is may be attached to this
// migration to migrate KV invoices to the native SQL
// schema. This is optional and can be disabled by the
// user if necessary.
},
}
)