Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

invoices: refactor InvoiceDB to eliminate ScanInvoices #8081

Merged
merged 5 commits into from Oct 19, 2023

Conversation

bhandras
Copy link
Collaborator

@bhandras bhandras commented Oct 11, 2023

This PR removes ScanInvoices from InvoiceDB (and the channeldb implementation) and adds two specific methods that can be expressed in SQL more efficiently. Builds on top of #8066 and is a pre-requirement for #8052

The downside of the refactor is that for k/v implementations we'll need to scan invoices twice, but since we're fully migrating to SQL this is just a temporary issue.

Part of #6288

Copy link
Collaborator

@ellemouton ellemouton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very slick PR 🔥

Just one comment regarding returning nil instead of an error from DeleteCanceledInvoices so that we dont error on startup if there are no invoices yet.

Other than that - LGTM

channeldb/invoices.go Outdated Show resolved Hide resolved
channeldb/invoices.go Outdated Show resolved Hide resolved
channeldb/invoices.go Outdated Show resolved Hide resolved
invoices/invoiceregistry.go Show resolved Hide resolved
invoices/invoiceregistry.go Show resolved Hide resolved
Copy link
Collaborator

@ellemouton ellemouton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice 🔥 LGTM

Copy link
Collaborator

@yyforyongyu yyforyongyu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice refactoring PR! My major comment is to change the deletion behavior of DeleteCanceledInvoices, that it shouldn't perform queries check to return an error and instead should be an noop like other Delete methods.


db, err := MakeTestInvoiceDB(t, OptionClock(testClock))
require.NoError(t, err, "unable to make test db")

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we also add a case here to test the empty slice returned from FetchPendingInvoices?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah good idea! Done.

channeldb/invoice_test.go Show resolved Hide resolved
invoiceIndexBucket,
)
if invoiceIndex == nil {
return invpkg.ErrNoInvoicesCreated
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think we should unify the behaviors here - in FetchPendingInvoices we'd ignore this error, and we should. do the same here? In general I think DeleteCanceledInvoices should be a NOOP if there are no invoices in the db, instead of returning an error.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This case is different though right? We do return nil above when we "open" the read-write bucket invoices however if that exist, we should assume that both the the invoice index and add index exists.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could it be the case that this is just an empty bucket? like all the invoices are deleted?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, if the bucket is empty we'd still get back the handle.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool - then I'm curious in what case will this ErrNoInvoicesCreated be returned?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's there to give us some reassurance that about expected existence of those buckets. Similar checks are done for other channeldb methods too.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool then I interpret it as a db corruption check.

@@ -2761,6 +2761,102 @@ func delAMPSettleIndex(invoiceNum []byte, invoices,
return nil
}

// DeleteCanceledInvoices deletes all canceled invoices from the database.
func (d *DB) DeleteCanceledInvoices(_ context.Context) error {
return kvdb.Update(d, func(tx kvdb.RwTx) error {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use batch here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's probably not a good idea since we scan through all the invoices here and bolt's Batch method assumes that the closure can be executed multiple times since it'll only try to parallelize optimistically (given bolt has no idea about what we do here).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it depends on whether there's an error and how we handle the error, from this bench test, if we distinguish the errors here, each closure is executed exactly once.

@@ -3092,6 +3079,65 @@ func TestDeleteInvoices(t *testing.T) {
assertInvoiceCount(0)
}

// TestDeleteCanceledInvoices tests that deleting canceled invoices with the
// specific DeleteCanceledInvoices method works correctly.
func TestDeleteCanceledInvoices(t *testing.T) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it'd be great if we could add tests to cover more branches in this method, but guess it's too much work as most stuff here is not mocked.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, maybe we should return to the test coverage question later on once we have both SQL and KV implementations run against this test suite since I'm afraid many of the branches we'd test will go away as we deprecate the KV implementation. Similarly TestDeleteInvoices is also very barebones, so perhaps a bigger overhaul is necessary.

In this commit we change how we select invoices to follow or delete when
starting the InvoiceRegistry to instead of using the deperecated scan
func from channeldb, use specific functions to gather pending and delete
canceled invoices.
Copy link
Collaborator

@yyforyongyu yyforyongyu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Also love the green CI!

Copy link
Collaborator

@saubyk saubyk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack

@guggero guggero disabled auto-merge October 19, 2023 09:27
@guggero guggero merged commit 812f4d9 into lightningnetwork:master Oct 19, 2023
24 of 25 checks passed
@bhandras bhandras deleted the invoicedb-refactor branch October 19, 2023 09:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

None yet

5 participants