-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
refactor: move graph responsibilities from routing.ChannelRouter to new graph.Builder #8848
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 as PR comments)
Additionally, you can add CodeRabbit Configration File (
|
649fff5
to
44c6007
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.
Great PR! Particularly like the attention to detail re the commit structure to make some of the larger mostly-move commits easier to follow.
Will do another pass, but at initial glance, the main thing that jumped out at me is if we're able to eliminate awareness of the underlying graph db transaction RwTx
from the interface all together. We may be able to wrap things in a sort of graphSession
to abstract away those details, and give the future SQL schema for the graph a foil.
c588ba0
to
25593ae
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 👍 for the extra indirection, it was a bit of a mind bend so added a temporary (rough) commit at the end to see if this is what you had in mind.
// topology is synchronized. | ||
// | ||
//nolint:interfacebloat | ||
type ChannelGraphSource interface { |
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.
@Roasbeef - if we go with the "put interface where it is used" pattern, shall I go ahead an move this to the gossiper instead?
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 what I've experienced I think we usually go with the "put interface where it is implemented" tho.
092aee1
to
009d60d
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 again @Roasbeef - I think this new iteration is looking a bit better (again see last temp commit) 🙏
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.
Dig the latest approach. This way the interface the router declares has no direct references to the kvdb
paradigm.
f905ced
to
c9818f3
Compare
Thanks for the review @Roasbeef 🚀 Squashed in the latest approach - this is ready for another look 👍 |
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.
Reviewed 12 of 24 files at r1, 29 of 29 files at r2, 32 of 38 files at r4, 8 of 8 files at r5, 17 of 17 files at r6, all commit messages.
Reviewable status: all files reviewed, 23 unresolved discussions (waiting on @djkazic, @ellemouton, and @yyforyongyu)
channeldb/graphsession/graph_session.go
line 51 at r6 (raw file):
type Session struct { graph graph tx kvdb.RTx
Is the intent that a new DB backend implement an entirely new Session
struct? As is, the references to kvdb.RTx
still exist, forcing awareness of the old paradigm.
One potentially slim way to add this extra lay of direction would be to create a new interface in place of kvdb.RTx
. This would represent an abstract notion of a transaction within the context of this graph, not necessarily tied to the underlying database.
The end-goal here as I perceive it is that this package makes no direct reference to the current DB abstractions. Instead way might have a struct that lives on the top level lnd
package, which serves as a sort of glue/adapter between the old worlds and new.
channeldb/graphsession/graph_session.go
line 131 at r6 (raw file):
// // Unknown policies are passed into the callback as nil values. ForEachNodeDirectedChannel(tx kvdb.RTx, node route.Vertex,
Re the comment above, rather than calling NewPathFindTx()
to generate a tx, to then pass into this method, this would be hidden in a private attribute by a concrete implementation of the interface.
Or we add a layer of indirection here with a custom db tx interface.
In this commit, we further reduce the routingGraph interface and this time we make it more node-agnostic so that it can be backed by any graph and not one with a concept of "sourceNode".
In preparation for structs outside of the `routing` package implementing this interface, export `routingGraph` and rename it to `Graph` so as to avoid stuttering.
In preparation for the next commit.
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 all ! updated :)
tx kvdb.RTx | ||
} | ||
|
||
// NewRoutingGraph constructs a Session that which does not first start a |
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.
e we should make that assumption more clear on the
cool - updated the comment 👍
// up to the caller. | ||
// | ||
// Unknown policies are passed into the callback as nil values. | ||
ForEachNodeDirectedChannel(tx kvdb.RTx, node route.Vertex, |
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 - thanks for the suggestion - added!
NextPaymentID: sequencer.NextID, | ||
PathFindingConfig: pathFindingConfig, | ||
Clock: clock.NewDefaultClock(), | ||
ApplyChannelUpdate: s.graphBuilder.ApplyChannelUpdate, |
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 ok I see now that this is more inline with the first diagram you posted (ie the ideal vision)
so gonna leave this as is for now if that is ok and then we do that change later on?
routing/payment_session.go
Outdated
// Get a routing graph. | ||
routingGraph, cleanup, err := p.getRoutingGraph() | ||
// Get a routing graph session. | ||
routingGraph, err := p.graphSessFactory.NewSession() |
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.
added a commit!
graph/builder.go
Outdated
|
||
// Builder builds and maintains a view of the Lightning Network graph. | ||
type Builder struct { | ||
started uint32 // To be used atomically. |
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 added a commit at the end to convert the other Builder members to use atomic.Unit*
|
||
// logClosure is used to provide a closure over expensive logging operations so | ||
// don't have to be performed when the logging level doesn't warrant it. | ||
type logClosure func() string |
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.
for this line:
log.Tracef("New channel update applied: %v",
newLogClosure(func() string { return spew.Sdump(msg) }))
In this commit, we completely remove the Router's dependence on a Graph source that requires a `kvdb.RTx`. In so doing, we are more prepared for a future where the Graph source is backed by different DB structure such as pure SQL. The two areas affected here are: the ChannelRouter's graph access that it uses for pathfinding. And the SessionSource's graph access that it uses for payments. The ChannelRouter gets given a Graph and the SessionSource is given a GraphSessionFactory which it can use to create a new session. Behind the scenes, this will acquire a kvdb.RTx that will be used for calls to the Graph's `ForEachNodeChannel` method.
Instead of querying it from the graph since this will be removed in a future commit.
In preparation for having a clean graph DB interface, refactor FetchChanInfos so that no transaction can be provided.
In preparation for adding a clean Graph DB interface, we create a version of FetchLightningNode that doesnt allow a caller to provide in a transaction.
In prep for a clean Graph DB interface, we add a version of ForEachNodeChannel that does not take in an existing db transaction.
... to the new `graph` package in preparation for the implementation of the interface being moved to this new package.
..which describes the database methods that are required for graph maintaining and building.
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🌊⛵️ (looks like linter failed tho)
// up to the caller. | ||
// | ||
// Unknown policies are passed into the callback as nil values. | ||
ForEachNodeDirectedChannel(tx kvdb.RTx, node route.Vertex, |
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.
ok I see what's going on here now - so graph
is like a placeholder to access the methods defined in channebldb
, aliasing the two methods. Feels a bit weird but guess it's ok.
tx kvdb.RTx | ||
} | ||
|
||
// NewRoutingGraph constructs a Session that which does not first start a |
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.
Q: why do we want to maintain a db tx ourselves in the first place?
// can then be used for a path-finding session. Depending on the implementation, | ||
// the GraphSession will represent a DB connection where a read-lock is being | ||
// held across calls to the backing Graph. | ||
type GraphSessionFactory interface { |
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 let's keep the PR a pure refactor.
"github.com/lightningnetwork/lnd/routing/route" | ||
) | ||
|
||
// ChannelGraphSource represents the source of information about the topology |
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 it's just a nit so feel free to ignore - and yes agree the approach if you plan to as it makes reviewing way easier.
graph/builder.go
Outdated
|
||
// Builder builds and maintains a view of the Lightning Network graph. | ||
type Builder struct { | ||
started uint32 // To be used atomically. |
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.
Or atomic.Bool
?
graph/builder.go
Outdated
// Start launches all the goroutines the Builder requires to carry out its | ||
// duties. If the builder has already been started, then this method is a noop. | ||
func (b *Builder) Start() error { | ||
if !b.started.CompareAndSwap(0, 1) { |
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.
I'm proposing a new pattern to start/stop systems here, so the idea is,
- always log
starting...
inStart
. - return an error when it's called twice.
This is to help us debug issues in the future, same for Stop
. No need to change here tho, just wanna bring awareness that this discussion is going on.
|
||
// logClosure is used to provide a closure over expensive logging operations so | ||
// don't have to be performed when the logging level doesn't warrant it. | ||
type logClosure func() string |
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.
think the linter will throw an error if it isn't used?
|
||
// ApplyChannelUpdate validates a channel update and if valid, applies it to the | ||
// database. It returns a bool indicating whether the updates were successful. | ||
func (b *Builder) ApplyChannelUpdate(msg *lnwire.ChannelUpdate) bool { |
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.
I see the other place uses s.graphBuilder.ApplyChannelUpdate,
, and wonder if we should also replace s.applyChannelUpdate
with this newer method.
@@ -294,6 +294,12 @@ func (p *paymentSession) RequestRoute(maxAmt, feeLimit lnwire.MilliSatoshi, | |||
// attempt, because concurrent payments may change balances. | |||
bandwidthHints, err := p.getBandwidthHints(graph) | |||
if err != nil { | |||
// Close routing graph session. | |||
if graphErr := closeGraph(); graphErr != nil { |
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.
🙏
5b8c54e
to
048e4ba
Compare
This is preparation for an upcoming commit that will move over various responsibilities from the ChannelRouter to the graph Builder. So that that commit can be a pure code-move commit, the template for the new sub-system is added up front here.
This commit is a large refactor that moves over various responsibilities from the ChannelRouter to the graph.Builder. These include all graph related tasks such as: - graph pruning - validation of new network updates & persisting new updates - notifying topology update clients of any changes. This is a large commit but: - many of the files are purely moved from `routing` to `graph` - the business logic put in the graph Builder is copied exactly as is from the ChannelRouter with one exception: - The ChannelRouter just needs to be able to call the Builder's `ApplyChannelUpdate` method. So this is now exported and provided to the ChannelRouter as a config option. - The trickiest part was just moving over the test code since quite a bit had to be duplicated.
This is done in a separate commit so as to keep the original code-move commit mostly a pure code move.
Instead of relying on devs to remember that they must only be accessed atomically.
Ensure that the graph session used during pathfinding is properly closed if the call to getBandwidthHints fails.
Also move incorrect entry from 18.2 to 18.3
Note that the two required failing tests (unit cover and neutrino itest) are failing at result-upload time. The actual checks have passed. |
This PR achieves 2 goals:
Moves graph building and maintaining responsibilities from the
ChannelRouter
to the newgraph.Builder
. These responsibilities include:Removes the
ChannelRouter
's direct access to thechanneldb.ChannelGraph
pointer and replace it with an interface instead. This will open up the possibility of providing various other types of graph backends.This chips away at the first few steps noted in issue #8833 and also takes a step towards #8835 since with this PR, the ChannelRouter now only does path finding and payments.
This change is