invoices: migrate KV invoices to native SQL for users of KV SQL backends#8831
invoices: migrate KV invoices to native SQL for users of KV SQL backends#8831guggero merged 21 commits intolightningnetwork:masterfrom
Conversation
|
Important Review skippedAuto reviews are limited to specific labels. 🏷️ Labels to auto review (1)
Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
6682b50 to
338e1f0
Compare
d2a329f to
6379a8b
Compare
5fe92e2 to
a7bf598
Compare
b6f0ac8 to
b983851
Compare
b983851 to
706b444
Compare
96f0cbe to
bfe4ad5
Compare
sqldb/no_sqlite.go
Outdated
| return s.BaseDB | ||
| } | ||
|
|
||
| // ApplyAllMigrations applices both the SQLC and custom in-code migrations to |
There was a problem hiding this comment.
spelling: applices -> applies, and 2 other instances where this function was implemented
There was a problem hiding this comment.
Thank you! Fixed.
| params := sqlc.InsertInvoiceParams{ | ||
| Hash: paymentHash[:], | ||
| AmountMsat: int64(invoice.Terms.Value), | ||
| CltvDelta: sqldb.SQLInt32( |
There was a problem hiding this comment.
Just noticed the comment: // Note: BOLT12 invoices don't have a final cltv delta. is no longer there
invoices/sql_migration.go
Outdated
| // which is a monotonically increasing uint32. | ||
| invoiceBucket = []byte("invoices") | ||
|
|
||
| // paymentHashIndexBucket is the name of the sub-bucket within the |
There was a problem hiding this comment.
The comment references paymentHashIndexBucket, while the variable is actually named invoiceIndexBucket. Is this discrepancy intentional?
ziggie1984
left a comment
There was a problem hiding this comment.
LGTM 🫶, massive effort in this PR, and also shout-out to Elle's great ideas here.
Had some minor comments but nothing blocking.
Would be great to open some follow-up issues for the stuff we want to move into another PR.
| -- only run once. It tracks a global database version that encompasses both | ||
| -- schema migrations handled by golang-migrate and custom in-code migrations | ||
| -- for more complex data conversions that cannot be expressed in pure SQL. | ||
| CREATE TABLE IF NOT EXISTS migration_tracker ( |
There was a problem hiding this comment.
does this mean, this migration_tracker table is always greater or equal to the schema migration table of the sql table ? Because the in-code migration will lead to the version being greater but the version in this table cannot be lower than the version that the schema migration correct ?
There was a problem hiding this comment.
Correct! There's a possibility that we could just rely in Golang Migrate in the future once this PR has landed (if ever): golang-migrate/migrate#932
| // version. If a migration includes a non-nil MigrationFn, it is executed after | ||
| // the SQL schema has been migrated to the corresponding schema version. |
There was a problem hiding this comment.
Does this still hold true if for every code migration will be done within a separate migration so that we do not have schema-migration and normal version in the same version ?
There was a problem hiding this comment.
Yes, a migration can be of three types: "schema-only", "schema and in-code" or "in-code-only". If a migration function is defined, the schema version acts as a prerequisite for the migration. This means the schema is always updated to the required version first.
sqldb/migrations.go
Outdated
| type MigrationExecutor interface { | ||
| // CurrentSchemaVersion returns the current schema version of the | ||
| // database. | ||
| CurrentSchemaVersion() (int, error) |
There was a problem hiding this comment.
haven't seen a code part where this function is used ?
There was a problem hiding this comment.
Indeed this is not used anymore. Great catch! Removed.
|
|
||
| // ExecuteMigrations runs migrations for the database, depending on the | ||
| // target given, either all migrations or up to a given version. | ||
| ExecuteMigrations(target MigrationTarget) error |
There was a problem hiding this comment.
Nit: Maybe add here in the comment that this function handles the schema and in-code migration, and maybe recommend that migrations schema or in-code should be done separately ?
| migrationConfig = []MigrationConfig{ | ||
| { | ||
| Name: "000001_invoices", | ||
| Version: 1, |
There was a problem hiding this comment.
does the schema version always correspond to the filename here, meaning that would we start with 000002 in the firt place the database version would start at 2 ?
There was a problem hiding this comment.
Yes the schema version should always correspond to the filename. This is only used to ensure clean ordering.
|
|
||
| offset := uint64(0) | ||
| t0 := time.Now() | ||
| // Create the hash index which we will use to look up invoice |
There was a problem hiding this comment.
would it be difficult to inject in at runtime @bhandras
| // disabled, the regular native SQL store migrations will still | ||
| // run. If the database version is already above this custom | ||
| // migration's version (6), it will be skipped permanently, | ||
| // regardless of the flag. |
There was a problem hiding this comment.
Hmm so if the user disables this, and we add a new migration in the future (version 7) he will not be able to migrate the invoice ?
There was a problem hiding this comment.
The idea is that users won't disable the invoice migration unless the it fails for them. In that case they can continue using their node and report a bug to us and they should be able to migrate later on.
| // testNativeSQLNoMigration tests that nodes that have invoices would not start | ||
| // up with native SQL enabled, as we don't currently support migration of KV | ||
| // invoices to the new SQL schema. | ||
| func testNativeSQLNoMigration(ht *lntest.HarnessTest) { |
There was a problem hiding this comment.
Create an issue for this because this will be done in a followu up ?
|
|
||
| if len(htlcs) > 0 { | ||
| invoice.Htlcs = htlcs | ||
| var amountPaid lnwire.MilliSatoshi |
There was a problem hiding this comment.
Open an issue to investigate this behavior ?
There was a problem hiding this comment.
Discussed offline, we'll open the issue soon.
| invoice.Htlcs = htlcs | ||
| var amountPaid lnwire.MilliSatoshi | ||
| for _, htlc := range htlcs { | ||
| if htlc.State == HtlcStateSettled { |
There was a problem hiding this comment.
I think we just need to adopt it and also add it if the htlc is in the accepted state, rather then removing it?
lnd/invoices/update_invoice.go
Lines 370 to 379 in 1b0f41d
or maybe remove it because it might be error pruning and we haven't tested every case.
There was a problem hiding this comment.
tested it locally it does work with this change:
for _, htlc := range htlcs {
if htlc.State == HtlcStateSettled ||
htlc.State == HtlcStateAccepted {
amountPaid += htlc.Amt
}
}
invoice.AmtPaid = amountPaid
There was a problem hiding this comment.
Tested it with go test -v -run=TestMigrationWithChannelDB -tags=kvdb_sqlite and i think the only correct fix given your db is to use the stored amount paid value. Also discussed this offline.
|
@Roasbeef: review reminder |
This commit adds the migration_tracker table which we'll use to track if a custom migration has already been done.
This commit introduces support for custom, in-code migrations, allowing a specific Go function to be executed at a designated database version during sqlc migrations. If the current database version surpasses the specified version, the migration will be skipped.
This commit separates the execution of SQL and in-code migrations from their construction. This change is necessary because, currently, the SQL schema is migrated during the construction phase in the lncfg package. However, migrations are typically executed when individual stores are constructed within the configuration builder.
Previously we intentially did not set settled_at and settle_index when inserting a new invoice as those fields are set when we settle an invoice through the usual invoice update. As migration requires that we set these nullable fields, we can safely add them.
Certain invoices may not have a deterministic payment hash. For such invoices we still store the payment hashes in our KV database, but we do not have a sufficient index to retrieve them. This PR adds such index to the SQL database that will be used during migration to retrieve payment hashes.
…a hash The current sqlc GetInvoice query experiences incremental slowdowns during the migration of large invoice databases, primarily due to its complex predicate set. For this specific use case, a streamlined GetInvoiceByHash function provides a more efficient solution, maintaining near-constant lookup times even with extensive table sizes.
This commit runs the invoice migration if the user has a KV SQL backend configured.
Previously we'd recalculate the paid amount by summing amounts of settled HTLCs. This approach while correct would stop the SQL migration process as some KV invoices may have incorrectly stored paid amounts.
Previously, we applied replacements to our schema definitions to make them compatible with both SQLite and Postgres backends, as the files were not fully compatible with either. With this change, the only replacement required for SQLite has been moved to the generator script. This adjustment ensures compatibility by enabling auto-incrementing primary keys that are treated as 64-bit integers by sqlc.
|
The "Check commits" CI step succeeded locally, probably just too many commits for GitHub. |
|
reminder that we can remove this replace now: Line 210 in e403243 |
Change Description
This pull request adds the migration of old key-value (KV) invoices to the new native SQL schema when the --db.use-native-sql flag is set, unless the --db.skip-sql-invoice-migration flag is also specified.
Please note that since we currently do not support running on mixed database backends for users of
bboltoretcd, an additional step is required to migrate their KV database to SQL first. For more context, please see lightninglabs/lndinit#21.