-
Notifications
You must be signed in to change notification settings - Fork 186
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
multi: introduce a batch filter writer #274
Conversation
12d007d
to
4f2cabe
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very cool optimization⚡️ Left some comments on the usage of Batch
and questions about the method manageNewItems
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
from 4m25s to 4.2s
🔥
Those are amazing improvements Elle 🎉
It looks like we can be optimistic when we fetch the filters and assume "eventually they will be persisted". Worst case scenario we will ask for them again, but if we use sensitive default for flushing to disk it should not be a problem.
My main concern is about the concurrent queue. Isn't a simple struct with a slice + a lock enough for this?
filterdb/db.go
Outdated
var targetBucket walletdb.ReadWriteBucket | ||
switch filterData.Type { | ||
case RegularFilter: | ||
targetBucket = filters.NestedReadWriteBucket( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: instead of calling NestedReadWriteBucket
in every iteration we can call it once before the loop and change targetBucket in the switch statement. Now we have only two optio: regBucket or error but this would work even if we add more in the future
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah yes, great idea - updated 👍
972afbd
to
9a991c7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the review everyone! 🙏
You guys were completely right about just using a slice for the batch writer :) I was too trigger happy with the channel 😂
Updated accordingly!
It looks like we can be optimistic when we fetch the filters and assume "eventually they will be persisted". Worst case scenario we will ask for them again
Yes exactly :)
filterdb/db.go
Outdated
var targetBucket walletdb.ReadWriteBucket | ||
switch filterData.Type { | ||
case RegularFilter: | ||
targetBucket = filters.NestedReadWriteBucket( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah yes, great idea - updated 👍
Hello @ellemouton may I please ask how you timed this? |
@Chinwendu20 - I set up a regtest node & mined a bunch of blocks. Then I connected to it with that script i sent you in slack the other day and would time how long the rescan of those blocks would take. Note that for header syncing (which is what I believe you are working on), you would just want to time that part & not the rescan. |
9a991c7
to
cca7080
Compare
Lint the files and update the tests to use the `require` package.
Add a new FilterData type that encapsulates the filter, blockhash and type associated with a filter. This is done in order to prepare for a commit that will enable batch writes of these filters.
cca7080
to
5c5c7bd
Compare
@yyforyongyu & @positiveblue - this is ready! The dependant PR has been merged. PTAL 🙏 |
@Roasbeef: review reminder |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 🏐
One small suggestion to use list.List[T]
chanutils/queue.go
Outdated
|
||
chanIn chan T | ||
chanOut chan T | ||
overflow *list.List |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can use this generic list to inherit type safety (or sort of push down the concerns to another layer):
Lines 62 to 63 in 5aac983
// NewList returns an initialized list. | |
func NewList[V any]() *List[V] { return new(List[V]).Init() } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh sweet - that is perfect. Updated!
5c5c7bd
to
0ad438c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @Roasbeef! updated. Also updated the LND PR pointing to this 👍
chanutils/queue.go
Outdated
|
||
chanIn chan T | ||
chanOut chan T | ||
overflow *list.List |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh sweet - that is perfect. Updated!
0ad438c
to
a0f373f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM🥳 and def impressive optimization😻
|
||
// Stop the ticker since we don't want it to tick unless there is at | ||
// least one item in the queue. | ||
ticker.Stop() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: there's a near-impossible case, that if the DBWritesTickerDuration
is extremely small, we may end up having a tick already inside ticker
, causing an immediate write - no big deal here. But in a hindsight it looks like the lnd/ticker
package is more suitable for this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cool yeah im happy to update to the lnd ticker.
The only reason not to would be for performance reasons: this ticker stops and starts the same one the whole time while the LND one keeps creating new ones & discarding old ones.
So maybe makes sense to keep as is? Agreed re the possible immediate write but also agree that it is not a big deal 👍
lemme know :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also doesnt really make sense to make the DBWritesTickerDuration
too small cause then the batching benefits are lost
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah i think it's fine to leave it as-is, in the future we can add some config sanity check to make sure it won't happen - or let it happen, worse case we get an immediate call to the batch write.
a0f373f
to
4cd9538
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @yyforyongyu !
|
||
// Stop the ticker since we don't want it to tick unless there is at | ||
// least one item in the queue. | ||
ticker.Stop() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cool yeah im happy to update to the lnd ticker.
The only reason not to would be for performance reasons: this ticker stops and starts the same one the whole time while the LND one keeps creating new ones & discarding old ones.
So maybe makes sense to keep as is? Agreed re the possible immediate write but also agree that it is not a big deal 👍
lemme know :)
|
||
// Stop the ticker since we don't want it to tick unless there is at | ||
// least one item in the queue. | ||
ticker.Stop() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also doesnt really make sense to make the DBWritesTickerDuration
too small cause then the batching benefits are lost
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM⛵️
select { | ||
case item, ok := <-cq.chanIn: | ||
if !ok { | ||
log.Warnf("ConcurrentQueue " + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🙏
It seems like this change has not been reflected in btcwallet. I just rebased my branch and I could not run lnd with this new change because of this line of code in btcwallet @ellemouton I want to know if there is any way I can bypass this or if I am doing anything wrong. Thank you. |
This PR adds a generic
BatchWriter
which can be used to batch write items to a db.It persists the batch once the size reaches a certain threshold or if a ticker goes off
if at least one items is in the batch.
This
BatchWriter
is then used by theGetCFilter
method to persist filters that itgets during a query. This will improve the speed of the query since the
BatchWriter
isnon-blocking.
Performance Improvement
On current master branch, syncing 3200 filters on my local regtest network takes 4m25s
With this PR, syncing the same number of filters takes 4.2s
LND CI
LND CI with this PR is being tested here: lightningnetwork/lnd#7788