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:
Olaoluwa Osuntokun committed 2016-12-27 16:43:00 -08:00
1 parent 1c7f87c3f1
commit d5423f007d
2 files changed
+18 -5

No files matched your search

+17 -4
View File
@@ -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
+1 -1
View File
@@ -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) {