Skip to content

Commit e004447

Browse files
committed
multi: remove the need for the graphsession package
In this commit, we add a `GraphSession` method to the `ChannelGraph`. This method provides a caller with access to a `NodeTraverser`. This is used by pathfinding to create a graph "session" overwhich to perform a set of queries for a pathfinding attempt. With this refactor, we hide details such as DB transaction creation and transaction commits from the caller. So with this, pathfinding does not need to remember to "close the graph session". With this commit, the `graphsession` package may be completely removed.
1 parent dfe2314 commit e004447

11 files changed

+117
-297
lines changed

graph/db/graph.go

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -403,16 +403,6 @@ func initChannelGraph(db kvdb.Backend) error {
403403
return nil
404404
}
405405

406-
// NewPathFindTx returns a new read transaction that can be used for a single
407-
// path finding session. Will return nil if the graph cache is enabled.
408-
func (c *ChannelGraph) NewPathFindTx() (kvdb.RTx, error) {
409-
if c.graphCache != nil {
410-
return nil, nil
411-
}
412-
413-
return c.db.BeginReadTx()
414-
}
415-
416406
// AddrsForNode returns all known addresses for the target node public key that
417407
// the graph DB is aware of. The returned boolean indicates if the given node is
418408
// unknown to the graph DB or not.
@@ -3907,6 +3897,64 @@ func (c *ChannelGraph) IsClosedScid(scid lnwire.ShortChannelID) (bool, error) {
39073897
return isClosed, nil
39083898
}
39093899

3900+
// GraphSession will provide the call-back with access to a NodeTraverser
3901+
// instance which can be used to perform queries against the channel graph. If
3902+
// the graph cache is not enabled, then the call-back will be provided with
3903+
// access to the graph via a consistent read-only transaction.
3904+
func (c *ChannelGraph) GraphSession(cb func(graph NodeTraverser) error) error {
3905+
var (
3906+
tx kvdb.RTx
3907+
err error
3908+
commit = func() {}
3909+
)
3910+
if c.graphCache == nil {
3911+
tx, err = c.db.BeginReadTx()
3912+
if err != nil {
3913+
return err
3914+
}
3915+
3916+
commit = func() {
3917+
if err := tx.Rollback(); err != nil {
3918+
log.Errorf("Unable to rollback tx: %v", err)
3919+
}
3920+
}
3921+
}
3922+
defer commit()
3923+
3924+
return cb(&nodeTraverserSession{
3925+
db: c,
3926+
tx: tx,
3927+
})
3928+
}
3929+
3930+
// nodeTraverserSession implements the NodeTraverser interface but with a
3931+
// backing read only transaction for a consistent view of the graph in the case
3932+
// where the graph Cache has not been enabled.
3933+
type nodeTraverserSession struct {
3934+
tx kvdb.RTx
3935+
db *ChannelGraph
3936+
}
3937+
3938+
// ForEachNodeDirectedChannel calls the callback for every channel of the given
3939+
// node.
3940+
//
3941+
// NOTE: Part of the NodeTraverser interface.
3942+
func (c *nodeTraverserSession) ForEachNodeDirectedChannel(nodePub route.Vertex,
3943+
cb func(channel *DirectedChannel) error) error {
3944+
3945+
return c.db.ForEachNodeDirectedChannelTx(c.tx, nodePub, cb)
3946+
}
3947+
3948+
// FetchNodeFeatures returns the features of the given node. If the node is
3949+
// unknown, assume no additional features are supported.
3950+
//
3951+
// NOTE: Part of the NodeTraverser interface.
3952+
func (c *nodeTraverserSession) FetchNodeFeatures(nodePub route.Vertex) (
3953+
*lnwire.FeatureVector, error) {
3954+
3955+
return c.db.FetchNodeFeaturesTx(c.tx, nodePub)
3956+
}
3957+
39103958
func putLightningNode(nodeBucket kvdb.RwBucket, aliasBucket kvdb.RwBucket, // nolint:dupl
39113959
updateIndex kvdb.RwBucket, node *models.LightningNode) error {
39123960

graph/graphsession/graph_session.go

Lines changed: 0 additions & 137 deletions
This file was deleted.

routing/graph.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,15 @@ type Graph interface {
2121
FetchNodeFeatures(nodePub route.Vertex) (*lnwire.FeatureVector, error)
2222
}
2323

24-
// GraphSessionFactory can be used to produce a new Graph instance which can
25-
// then be used for a path-finding session. Depending on the implementation,
26-
// the Graph session will represent a DB connection where a read-lock is being
27-
// held across calls to the backing Graph.
24+
// GraphSessionFactory can be used to gain access to a graphdb.NodeTraverser
25+
// instance which can then be used for a path-finding session. Depending on the
26+
// implementation, the session will represent a DB connection where a read-lock
27+
// is being held across calls to the backing graph.
2828
type GraphSessionFactory interface {
29-
// NewGraphSession will produce a new Graph to use for a path-finding
30-
// session. It returns the Graph along with a call-back that must be
31-
// called once Graph access is complete. This call-back will close any
32-
// read-only transaction that was created at Graph construction time.
33-
NewGraphSession() (Graph, func() error, error)
29+
// GraphSession will provide the call-back with access to a
30+
// graphdb.NodeTraverser instance which can be used to perform queries
31+
// against the channel graph.
32+
GraphSession(cb func(graph graphdb.NodeTraverser) error) error
3433
}
3534

3635
// FetchAmountPairCapacity determines the maximal public capacity between two

routing/integrated_routing_context_test.go

Lines changed: 1 addition & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"time"
99

1010
"github.com/lightningnetwork/lnd/fn/v2"
11-
graphdb "github.com/lightningnetwork/lnd/graph/db"
1211
"github.com/lightningnetwork/lnd/kvdb"
1312
"github.com/lightningnetwork/lnd/lnwire"
1413
"github.com/lightningnetwork/lnd/routing/route"
@@ -211,7 +210,7 @@ func (c *integratedRoutingContext) testPayment(maxParts uint32,
211210

212211
session, err := newPaymentSession(
213212
&payment, c.graph.source.pubkey, getBandwidthHints,
214-
newMockGraphSessionFactory(c.graph), mc, c.pathFindingCfg,
213+
c.graph, mc, c.pathFindingCfg,
215214
)
216215
if err != nil {
217216
c.t.Fatal(err)
@@ -317,88 +316,3 @@ func getNodeIndex(route *route.Route, failureSource route.Vertex) *int {
317316
}
318317
return nil
319318
}
320-
321-
type mockGraphSessionFactory struct {
322-
Graph
323-
}
324-
325-
func newMockGraphSessionFactory(graph Graph) GraphSessionFactory {
326-
return &mockGraphSessionFactory{Graph: graph}
327-
}
328-
329-
func (m *mockGraphSessionFactory) NewGraphSession() (Graph, func() error,
330-
error) {
331-
332-
return m, func() error {
333-
return nil
334-
}, nil
335-
}
336-
337-
var _ GraphSessionFactory = (*mockGraphSessionFactory)(nil)
338-
var _ Graph = (*mockGraphSessionFactory)(nil)
339-
340-
type mockGraphSessionFactoryChanDB struct {
341-
graph *graphdb.ChannelGraph
342-
}
343-
344-
func newMockGraphSessionFactoryFromChanDB(
345-
graph *graphdb.ChannelGraph) *mockGraphSessionFactoryChanDB {
346-
347-
return &mockGraphSessionFactoryChanDB{
348-
graph: graph,
349-
}
350-
}
351-
352-
func (g *mockGraphSessionFactoryChanDB) NewGraphSession() (Graph, func() error,
353-
error) {
354-
355-
tx, err := g.graph.NewPathFindTx()
356-
if err != nil {
357-
return nil, nil, err
358-
}
359-
360-
session := &mockGraphSessionChanDB{
361-
graph: g.graph,
362-
tx: tx,
363-
}
364-
365-
return session, session.close, nil
366-
}
367-
368-
var _ GraphSessionFactory = (*mockGraphSessionFactoryChanDB)(nil)
369-
370-
type mockGraphSessionChanDB struct {
371-
graph *graphdb.ChannelGraph
372-
tx kvdb.RTx
373-
}
374-
375-
func newMockGraphSessionChanDB(graph *graphdb.ChannelGraph) Graph {
376-
return &mockGraphSessionChanDB{
377-
graph: graph,
378-
}
379-
}
380-
381-
func (g *mockGraphSessionChanDB) close() error {
382-
if g.tx == nil {
383-
return nil
384-
}
385-
386-
err := g.tx.Rollback()
387-
if err != nil {
388-
return fmt.Errorf("error closing db tx: %w", err)
389-
}
390-
391-
return nil
392-
}
393-
394-
func (g *mockGraphSessionChanDB) ForEachNodeDirectedChannel(nodePub route.Vertex,
395-
cb func(channel *graphdb.DirectedChannel) error) error {
396-
397-
return g.graph.ForEachNodeDirectedChannelTx(g.tx, nodePub, cb)
398-
}
399-
400-
func (g *mockGraphSessionChanDB) FetchNodeFeatures(nodePub route.Vertex) (
401-
*lnwire.FeatureVector, error) {
402-
403-
return g.graph.FetchNodeFeaturesTx(g.tx, nodePub)
404-
}

routing/integrated_routing_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,5 +404,5 @@ func TestPaymentAddrOnlyNoSplit(t *testing.T) {
404404
// The payment should have failed since we need to split in order to
405405
// route a payment to the destination, but they don't actually support
406406
// MPP.
407-
require.Equal(t, err.Error(), errNoPathFound.Error())
407+
require.ErrorIs(t, err, errNoPathFound)
408408
}

routing/mock_graph_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,17 @@ func (m *mockGraph) FetchNodeFeatures(nodePub route.Vertex) (
227227
return lnwire.EmptyFeatureVector(), nil
228228
}
229229

230+
// GraphSession will provide the call-back with access to a
231+
// graphdb.NodeTraverser instance which can be used to perform queries against
232+
// the channel graph.
233+
//
234+
// NOTE: Part of the GraphSessionFactory interface.
235+
func (m *mockGraph) GraphSession(
236+
cb func(graph graphdb.NodeTraverser) error) error {
237+
238+
return cb(m)
239+
}
240+
230241
// htlcResult describes the resolution of an htlc. If failure is nil, the htlc
231242
// was settled.
232243
type htlcResult struct {

0 commit comments

Comments
 (0)