Merge pull request #3197 from breez/optimize_prune_zombie_channels

Optimize prune zombie channels
This commit is contained in:
Olaoluwa Osuntokun
2019-07-18 20:56:56 -07:00
committed by GitHub
5 changed files with 256 additions and 39 deletions

View File

@@ -760,22 +760,31 @@ func (r *ChannelRouter) syncGraphWithChain() error {
// usually signals that a channel has been closed on-chain. We do this
// periodically to keep a healthy, lively routing table.
func (r *ChannelRouter) pruneZombieChans() error {
var chansToPrune []uint64
chansToPrune := make(map[uint64]struct{})
chanExpiry := r.cfg.ChannelPruneExpiry
log.Infof("Examining channel graph for zombie channels")
// A helper method to detect if the channel belongs to this node
isSelfChannelEdge := func(info *channeldb.ChannelEdgeInfo) bool {
return info.NodeKey1Bytes == r.selfNode.PubKeyBytes ||
info.NodeKey2Bytes == r.selfNode.PubKeyBytes
}
// First, we'll collect all the channels which are eligible for garbage
// collection due to being zombies.
filterPruneChans := func(info *channeldb.ChannelEdgeInfo,
e1, e2 *channeldb.ChannelEdgePolicy) error {
// Exit early in case this channel is already marked to be pruned
if _, markedToPrune := chansToPrune[info.ChannelID]; markedToPrune {
return nil
}
// We'll ensure that we don't attempt to prune our *own*
// channels from the graph, as in any case this should be
// re-advertised by the sub-system above us.
if info.NodeKey1Bytes == r.selfNode.PubKeyBytes ||
info.NodeKey2Bytes == r.selfNode.PubKeyBytes {
if isSelfChannelEdge(info) {
return nil
}
@@ -800,34 +809,9 @@ func (r *ChannelRouter) pruneZombieChans() error {
}
}
isZombieChan := e1Zombie && e2Zombie
// If AssumeChannelValid is present and we've determined the
// channel is not a zombie, we'll look at the disabled bit for
// both edges. If they're both disabled, then we can interpret
// this as the channel being closed and can prune it from our
// graph.
if r.cfg.AssumeChannelValid && !isZombieChan {
var e1Disabled, e2Disabled bool
if e1 != nil {
e1Disabled = e1.IsDisabled()
log.Tracef("Edge #1 of ChannelID(%v) "+
"disabled=%v", info.ChannelID,
e1Disabled)
}
if e2 != nil {
e2Disabled = e2.IsDisabled()
log.Tracef("Edge #2 of ChannelID(%v) "+
"disabled=%v", info.ChannelID,
e2Disabled)
}
isZombieChan = e1Disabled && e2Disabled
}
// If the channel is not considered zombie, we can move on to
// the next.
if !isZombieChan {
if !e1Zombie || !e2Zombie {
return nil
}
@@ -835,25 +819,57 @@ func (r *ChannelRouter) pruneZombieChans() error {
info.ChannelID)
// TODO(roasbeef): add ability to delete single directional edge
chansToPrune = append(chansToPrune, info.ChannelID)
chansToPrune[info.ChannelID] = struct{}{}
return nil
}
err := r.cfg.Graph.ForEachChannel(filterPruneChans)
// If AssumeChannelValid is present we'll look at the disabled bit for both
// edges. If they're both disabled, then we can interpret this as the
// channel being closed and can prune it from our graph.
if r.cfg.AssumeChannelValid {
disabledChanIDs, err := r.cfg.Graph.DisabledChannelIDs()
if err != nil {
return fmt.Errorf("unable to get disabled channels ids "+
"chans: %v", err)
}
disabledEdges, err := r.cfg.Graph.FetchChanInfos(disabledChanIDs)
if err != nil {
return fmt.Errorf("unable to fetch disabled channels edges "+
"chans: %v", err)
}
// Ensuring we won't prune our own channel from the graph.
for _, disabledEdge := range disabledEdges {
if !isSelfChannelEdge(disabledEdge.Info) {
chansToPrune[disabledEdge.Info.ChannelID] = struct{}{}
}
}
}
startTime := time.Unix(0, 0)
endTime := time.Now().Add(-1 * chanExpiry)
oldEdges, err := r.cfg.Graph.ChanUpdatesInHorizon(startTime, endTime)
if err != nil {
return fmt.Errorf("unable to filter local zombie channels: "+
"%v", err)
return fmt.Errorf("unable to fetch expired channel updates "+
"chans: %v", err)
}
for _, u := range oldEdges {
filterPruneChans(u.Info, u.Policy1, u.Policy2)
}
log.Infof("Pruning %v zombie channels", len(chansToPrune))
// With the set of zombie-like channels obtained, we'll do another pass
// to delete them from the channel graph.
for _, chanID := range chansToPrune {
toPrune := make([]uint64, 0, len(chansToPrune))
for chanID := range chansToPrune {
toPrune = append(toPrune, chanID)
log.Tracef("Pruning zombie channel with ChannelID(%v)", chanID)
}
if err := r.cfg.Graph.DeleteChannelEdges(chansToPrune...); err != nil {
if err := r.cfg.Graph.DeleteChannelEdges(toPrune...); err != nil {
return fmt.Errorf("unable to delete zombie channels: %v", err)
}