graph: add ReadOnlyGraph interface to GraphSource interface

In this commit, we take the existing graphsession.ReadyOnlyGraph
interface and remove its usage of a kvdb.RTx and replace it with a more
abstract `RTx` interface type.

The new GraphSource interface is expanded to include the
graphsession.ReadOnlyGraph interface and the implementation of it,
DBSource, is expanded to include the new methods. It converts the
given RTx to the underlying kvdb read transaction where needed.
This commit is contained in:
Elle Mouton
2024-11-11 16:24:46 +02:00
parent 6c008ff8fb
commit aa2480464b
6 changed files with 135 additions and 15 deletions

View File

@@ -1,6 +1,14 @@
package sources
import graphdb "github.com/lightningnetwork/lnd/graph/db"
import (
"fmt"
graphdb "github.com/lightningnetwork/lnd/graph/db"
"github.com/lightningnetwork/lnd/graph/session"
"github.com/lightningnetwork/lnd/kvdb"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing/route"
)
// DBSource is an implementation of the GraphSource interface backed by a local
// persistence layer holding graph related data.
@@ -19,3 +27,102 @@ func NewDBGSource(db *graphdb.ChannelGraph) *DBSource {
db: db,
}
}
// NewPathFindTx returns a new read transaction that can be used for a single
// path finding session. Will return nil if the graph cache is enabled for the
// underlying graphdb.ChannelGraph.
//
// NOTE: this is part of the graphsession.ReadOnlyGraph interface.
func (s *DBSource) NewPathFindTx() (session.RTx, error) {
tx, err := s.db.NewPathFindTx()
if err != nil {
return nil, err
}
return newKVDBRTx(tx), nil
}
// ForEachNodeDirectedChannel iterates through all channels of a given node,
// executing the passed callback on the directed edge representing the channel
// and its incoming policy. If the callback returns an error, then the
// iteration is halted with the error propagated back up to the caller. An
// optional read transaction may be provided. If it is, then it will be cast
// into a kvdb.RTx and passed into the callback.
//
// Unknown policies are passed into the callback as nil values.
//
// NOTE: this is part of the graphsession.ReadOnlyGraph interface.
func (s *DBSource) ForEachNodeDirectedChannel(tx session.RTx,
node route.Vertex,
cb func(channel *graphdb.DirectedChannel) error) error {
kvdbTx, err := extractKVDBRTx(tx)
if err != nil {
return err
}
return s.db.ForEachNodeDirectedChannel(kvdbTx, node, cb)
}
// FetchNodeFeatures returns the features of a given node. If no features are
// known for the node, an empty feature vector is returned. An optional read
// transaction may be provided. If it is, then it will be cast into a kvdb.RTx
// and passed into the callback.
//
// NOTE: this is part of the graphsession.ReadOnlyGraph interface.
func (s *DBSource) FetchNodeFeatures(tx session.RTx,
node route.Vertex) (*lnwire.FeatureVector, error) {
kvdbTx, err := extractKVDBRTx(tx)
if err != nil {
return nil, err
}
return s.db.FetchNodeFeatures(kvdbTx, node)
}
// kvdbRTx is an implementation of graphdb.RTx backed by a KVDB database read
// transaction.
type kvdbRTx struct {
kvdb.RTx
}
// newKVDBRTx constructs a kvdbRTx instance backed by the given kvdb.RTx.
func newKVDBRTx(tx kvdb.RTx) *kvdbRTx {
return &kvdbRTx{tx}
}
// Close closes the underlying transaction.
//
// NOTE: this is part of the graphdb.RTx interface.
func (t *kvdbRTx) Close() error {
if t.RTx == nil {
return nil
}
return t.RTx.Rollback()
}
// MustImplementRTx is a helper method that ensures that the kvdbRTx type
// implements the RTx interface.
//
// NOTE: this is part of the graphdb.RTx interface.
func (t *kvdbRTx) MustImplementRTx() {}
// A compile-time assertion to ensure that kvdbRTx implements the RTx interface.
var _ session.RTx = (*kvdbRTx)(nil)
// extractKVDBRTx is a helper function that casts an RTx into a kvdbRTx and
// errors if the cast fails.
func extractKVDBRTx(tx session.RTx) (kvdb.RTx, error) {
if tx == nil {
return nil, nil
}
kvdbTx, ok := tx.(*kvdbRTx)
if !ok {
return nil, fmt.Errorf("expected a graphdb.kvdbRTx, got %T", tx)
}
return kvdbTx, nil
}