channeldb: add option to re-use existing db transaction for graph traversals
This commit modifies the LightningNode.ForEachChannel method to give the caller the option of re-using an existing database transaction instead of always creating a new db transaction with each invocation. Internally boltdb will run into an error/dead-lock if a nested transaction is attempted. Such an action might be attempted if one were to use the traversal functions in a path finding algorithm. Therefore in order to avoid that after, we now allow the re-use of transactions to facilitate nested calls to ForEachChannel.
This commit is contained in:
2 files changed
+18
-5
No files matched your search
+17
-4
@@ -632,11 +632,14 @@ func (c *ChannelGraph) FetchLightningNode(pub *btcec.PublicKey) (*LightningNode,
|
||||
// ForEachChannel iterates through all the outgoing channel edges from this
|
||||
// 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
|
||||
// propagated back up to the caller.
|
||||
func (l *LightningNode) ForEachChannel(cb func(*ChannelEdge) error) error {
|
||||
// propagated back up to the caller. If the caller wishes to re-use an existing
|
||||
// boltdb transaction, then it 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 traversal.
|
||||
func (l *LightningNode) ForEachChannel(tx *bolt.Tx, cb func(*ChannelEdge) error) error {
|
||||
nodePub := l.PubKey.SerializeCompressed()
|
||||
|
||||
return l.db.View(func(tx *bolt.Tx) error {
|
||||
traversal := func(tx *bolt.Tx) error {
|
||||
nodes := tx.Bucket(nodeBucket)
|
||||
if nodes == nil {
|
||||
return ErrGraphNotFound
|
||||
@@ -682,7 +685,17 @@ func (l *LightningNode) ForEachChannel(cb func(*ChannelEdge) error) error {
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// If no transaction was provided, then we'll create a new transaction
|
||||
// to execute the transaction within.
|
||||
if tx == nil {
|
||||
return l.db.View(traversal)
|
||||
}
|
||||
|
||||
// Otherwise, we re-use the existing transaction to execute the graph
|
||||
// traversal.
|
||||
return traversal(tx)
|
||||
}
|
||||
|
||||
// ChannelEdge represents a *directed* edge within the channel graph. For each
|
||||
|
||||
@@ -489,7 +489,7 @@ func TestGraphTraversal(t *testing.T) {
|
||||
// Finally, we want to test the ability to iterate over all the
|
||||
// outgoing channels for a particular node.
|
||||
numNodeChans := 0
|
||||
err = firstNode.ForEachChannel(func(c *ChannelEdge) error {
|
||||
err = firstNode.ForEachChannel(nil, func(c *ChannelEdge) error {
|
||||
// Each each should indicate that it's outgoing (pointed
|
||||
// towards the second node).
|
||||
if !c.Node.PubKey.IsEqual(secondNode.PubKey) {
|
||||
|
||||
Reference in new issue
Block a user