channeldb: modify ForEachNode/ForEachChannel to accept a db txn
This commit modifies the ForEachNode on the ChannelGraph and
ForEachChannel on the LightningNode struct to accept a database
transaction as its first argument. With this change, it’ll now be
possible to implement graph traversals that typically required a nested
loop with all the vertex loaded into memory using the callback API
instead:
c.ForEachNode(nil, func(tx, node) {
node.ForEachChannel(tx, func(…) {
})
})
This commit is contained in:
2 files changed
+37
-17
No files matched your search
+32
-15
@@ -217,11 +217,16 @@ func (c *ChannelGraph) ForEachChannel(cb func(*ChannelEdgeInfo, *ChannelEdgePoli
|
|||||||
// executing the passed callback with each node encountered. If the callback
|
// executing the passed callback with each node encountered. If the callback
|
||||||
// returns an error, then the transaction is aborted and the iteration stops
|
// returns an error, then the transaction is aborted and the iteration stops
|
||||||
// early.
|
// early.
|
||||||
func (c *ChannelGraph) ForEachNode(cb func(*LightningNode) error) error {
|
//
|
||||||
// TODO(roasbeef): need to also pass in a transaction? or reverse order
|
// If the caller wishes to re-use an existing boltdb transaction, then it
|
||||||
// to get all in memory THEN execute callback?
|
// should be passed as the first argument. Otherwise the first argument should
|
||||||
|
// be nil and a fresh transaction will be created to execute the graph
|
||||||
return c.db.View(func(tx *bolt.Tx) error {
|
// traversal
|
||||||
|
//
|
||||||
|
// TODO(roasbeef): add iterator interface to allow for memory efficient graph
|
||||||
|
// traversal when graph gets mega
|
||||||
|
func (c *ChannelGraph) ForEachNode(tx *bolt.Tx, cb func(*bolt.Tx, *LightningNode) error) error {
|
||||||
|
traversal := func(tx *bolt.Tx) error {
|
||||||
// First grab the nodes bucket which stores the mapping from
|
// First grab the nodes bucket which stores the mapping from
|
||||||
// pubKey to node information.
|
// pubKey to node information.
|
||||||
nodes := tx.Bucket(nodeBucket)
|
nodes := tx.Bucket(nodeBucket)
|
||||||
@@ -246,9 +251,19 @@ func (c *ChannelGraph) ForEachNode(cb func(*LightningNode) error) error {
|
|||||||
|
|
||||||
// Execute the callback, the transaction will abort if
|
// Execute the callback, the transaction will abort if
|
||||||
// this returns an error.
|
// this returns an error.
|
||||||
return cb(node)
|
return cb(tx, node)
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
|
|
||||||
|
// If no transaction was provided, then we'll create a new transaction
|
||||||
|
// to execute the transaction within.
|
||||||
|
if tx == nil {
|
||||||
|
return c.db.View(traversal)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, we re-use the existing transaction to execute the graph
|
||||||
|
// traversal.
|
||||||
|
return traversal(tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SourceNode returns the source node of the graph. The source node is treated
|
// SourceNode returns the source node of the graph. The source node is treated
|
||||||
@@ -962,13 +977,15 @@ func (c *ChannelGraph) HasLightningNode(pub *btcec.PublicKey) (time.Time, bool,
|
|||||||
// ForEachChannel iterates through all the outgoing channel edges from this
|
// ForEachChannel iterates through all the outgoing channel edges from this
|
||||||
// node, executing the passed callback with each edge as its sole argument. If
|
// node, executing the passed callback with each edge as its sole argument. If
|
||||||
// the callback returns an error, then the iteration is halted with the error
|
// the callback returns an error, then the iteration is halted with the error
|
||||||
// propagated back up to the caller. If the caller wishes to re-use an existing
|
// propagated back up to the caller.
|
||||||
// boltdb transaction, then it should be passed as the first argument.
|
//
|
||||||
// Otherwise the first argument should be nil and a fresh transaction will be
|
// If the caller wishes to re-use an existing boltdb transaction, then it
|
||||||
// created to execute the graph traversal.
|
// should be passed as the first argument. Otherwise the first argument should
|
||||||
func (l *LightningNode) ForEachChannel(tx *bolt.Tx, cb func(*ChannelEdgeInfo, *ChannelEdgePolicy) error) error {
|
// be nil and a fresh transaction will be created to execute the graph
|
||||||
// TODO(roasbeef): remove the option to pass in a transaction after
|
// traversal.
|
||||||
// all?
|
func (l *LightningNode) ForEachChannel(tx *bolt.Tx,
|
||||||
|
cb func(*bolt.Tx, *ChannelEdgeInfo, *ChannelEdgePolicy) error) error {
|
||||||
|
|
||||||
nodePub := l.PubKey.SerializeCompressed()
|
nodePub := l.PubKey.SerializeCompressed()
|
||||||
|
|
||||||
traversal := func(tx *bolt.Tx) error {
|
traversal := func(tx *bolt.Tx) error {
|
||||||
@@ -1021,7 +1038,7 @@ func (l *LightningNode) ForEachChannel(tx *bolt.Tx, cb func(*ChannelEdgeInfo, *C
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Finally, we execute the callback.
|
// Finally, we execute the callback.
|
||||||
if err := cb(edgeInfo, edgePolicy); err != nil {
|
if err := cb(tx, edgeInfo, edgePolicy); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/boltdb/bolt"
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
"github.com/roasbeef/btcd/btcec"
|
"github.com/roasbeef/btcd/btcec"
|
||||||
@@ -533,7 +534,7 @@ func TestGraphTraversal(t *testing.T) {
|
|||||||
|
|
||||||
// Iterate over each node as returned by the graph, if all nodes are
|
// Iterate over each node as returned by the graph, if all nodes are
|
||||||
// reached, then the map created above should be empty.
|
// reached, then the map created above should be empty.
|
||||||
err = graph.ForEachNode(func(node *LightningNode) error {
|
err = graph.ForEachNode(nil, func(_ *bolt.Tx, node *LightningNode) error {
|
||||||
delete(nodeIndex, node.Alias)
|
delete(nodeIndex, node.Alias)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@@ -630,7 +631,9 @@ func TestGraphTraversal(t *testing.T) {
|
|||||||
// Finally, we want to test the ability to iterate over all the
|
// Finally, we want to test the ability to iterate over all the
|
||||||
// outgoing channels for a particular node.
|
// outgoing channels for a particular node.
|
||||||
numNodeChans := 0
|
numNodeChans := 0
|
||||||
err = firstNode.ForEachChannel(nil, func(_ *ChannelEdgeInfo, c *ChannelEdgePolicy) error {
|
err = firstNode.ForEachChannel(nil, func(_ *bolt.Tx, _ *ChannelEdgeInfo,
|
||||||
|
c *ChannelEdgePolicy) error {
|
||||||
|
|
||||||
// Each each should indicate that it's outgoing (pointed
|
// Each each should indicate that it's outgoing (pointed
|
||||||
// towards the second node).
|
// towards the second node).
|
||||||
if !c.Node.PubKey.IsEqual(secondNode.PubKey) {
|
if !c.Node.PubKey.IsEqual(secondNode.PubKey) {
|
||||||
|
|||||||
Reference in new issue
Block a user