mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 09:53:54 +01:00
channeldb: avoid locking the graph cache while iterating channels
It may happen that we do pathfinding while also attempt to change the graph. In this case changing the database, channel state, graph while reading from the same sources may create deadlocks. To resolve this we change locking policy in the graph cache when pathfinding.
This commit is contained in:
parent
54584aabb6
commit
3df216f6c3
@ -401,10 +401,9 @@ func (c *GraphCache) UpdateChannel(info *ChannelEdgeInfo) {
|
||||
}
|
||||
}
|
||||
|
||||
// ForEachChannel invokes the given callback for each channel of the given node.
|
||||
func (c *GraphCache) ForEachChannel(node route.Vertex,
|
||||
cb func(channel *DirectedChannel) error) error {
|
||||
|
||||
// getChannels returns a copy of the passed node's channels or nil if there
|
||||
// isn't any.
|
||||
func (c *GraphCache) getChannels(node route.Vertex) []*DirectedChannel {
|
||||
c.mtx.RLock()
|
||||
defer c.mtx.RUnlock()
|
||||
|
||||
@ -428,6 +427,8 @@ func (c *GraphCache) ForEachChannel(node route.Vertex,
|
||||
return node
|
||||
}
|
||||
|
||||
i := 0
|
||||
channelsCopy := make([]*DirectedChannel, len(channels))
|
||||
for _, channel := range channels {
|
||||
// We need to copy the channel and policy to avoid it being
|
||||
// updated in the cache if the path finding algorithm sets
|
||||
@ -439,9 +440,30 @@ func (c *GraphCache) ForEachChannel(node route.Vertex,
|
||||
channelCopy.InPolicy.ToNodeFeatures = features
|
||||
}
|
||||
|
||||
if err := cb(channelCopy); err != nil {
|
||||
channelsCopy[i] = channelCopy
|
||||
i++
|
||||
}
|
||||
|
||||
return channelsCopy
|
||||
}
|
||||
|
||||
// ForEachChannel invokes the given callback for each channel of the given node.
|
||||
func (c *GraphCache) ForEachChannel(node route.Vertex,
|
||||
cb func(channel *DirectedChannel) error) error {
|
||||
|
||||
// Obtain a copy of the node's channels. We need do this in order to
|
||||
// avoid deadlocks caused by interaction with the graph cache, channel
|
||||
// state and the graph database from multiple goroutines. This snapshot
|
||||
// is only used for path finding where being stale is acceptable since
|
||||
// the real world graph and our representation may always become
|
||||
// slightly out of sync for a short time and the actual channel state
|
||||
// is stored separately.
|
||||
channels := c.getChannels(node)
|
||||
for _, channel := range channels {
|
||||
if err := cb(channel); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
|
Loading…
Reference in New Issue
Block a user