github.com/decred/dcrlnd@v0.7.6/routing/heap.go (about)

     1  package routing
     2  
     3  import (
     4  	"container/heap"
     5  
     6  	"github.com/decred/dcrlnd/channeldb"
     7  	"github.com/decred/dcrlnd/lnwire"
     8  	"github.com/decred/dcrlnd/routing/route"
     9  )
    10  
    11  // nodeWithDist is a helper struct that couples the distance from the current
    12  // source to a node with a pointer to the node itself.
    13  type nodeWithDist struct {
    14  	// dist is the distance to this node from the source node in our
    15  	// current context.
    16  	dist int64
    17  
    18  	// node is the vertex itself. This can be used to explore all the
    19  	// outgoing edges (channels) emanating from a node.
    20  	node route.Vertex
    21  
    22  	// amountToReceive is the amount that should be received by this node.
    23  	// Either as final payment to the final node or as an intermediate
    24  	// amount that includes also the fees for subsequent hops.
    25  	amountToReceive lnwire.MilliAtom
    26  
    27  	// incomingCltv is the expected absolute expiry height for the incoming
    28  	// htlc of this node. This value should already include the final cltv
    29  	// delta.
    30  	incomingCltv int32
    31  
    32  	// probability is the probability that from this node onward the route
    33  	// is successful.
    34  	probability float64
    35  
    36  	// weight is the cost of the route from this node to the destination.
    37  	// Includes the routing fees and a virtual cost factor to account for
    38  	// time locks.
    39  	weight int64
    40  
    41  	// nextHop is the edge this route comes from.
    42  	nextHop *channeldb.CachedEdgePolicy
    43  
    44  	// routingInfoSize is the total size requirement for the payloads field
    45  	// in the onion packet from this hop towards the final destination.
    46  	routingInfoSize uint64
    47  }
    48  
    49  // distanceHeap is a min-distance heap that's used within our path finding
    50  // algorithm to keep track of the "closest" node to our source node.
    51  type distanceHeap struct {
    52  	nodes []*nodeWithDist
    53  
    54  	// pubkeyIndices maps public keys of nodes to their respective index in
    55  	// the heap. This is used as a way to avoid db lookups by using heap.Fix
    56  	// instead of having duplicate entries on the heap.
    57  	pubkeyIndices map[route.Vertex]int
    58  }
    59  
    60  // newDistanceHeap initializes a new distance heap. This is required because
    61  // we must initialize the pubkeyIndices map for path-finding optimizations.
    62  func newDistanceHeap(numNodes int) distanceHeap {
    63  	distHeap := distanceHeap{
    64  		pubkeyIndices: make(map[route.Vertex]int, numNodes),
    65  		nodes:         make([]*nodeWithDist, 0, numNodes),
    66  	}
    67  
    68  	return distHeap
    69  }
    70  
    71  // Len returns the number of nodes in the priority queue.
    72  //
    73  // NOTE: This is part of the heap.Interface implementation.
    74  func (d *distanceHeap) Len() int { return len(d.nodes) }
    75  
    76  // Less returns whether the item in the priority queue with index i should sort
    77  // before the item with index j.
    78  //
    79  // NOTE: This is part of the heap.Interface implementation.
    80  func (d *distanceHeap) Less(i, j int) bool {
    81  	// If distances are equal, tie break on probability.
    82  	if d.nodes[i].dist == d.nodes[j].dist {
    83  		return d.nodes[i].probability > d.nodes[j].probability
    84  	}
    85  
    86  	return d.nodes[i].dist < d.nodes[j].dist
    87  }
    88  
    89  // Swap swaps the nodes at the passed indices in the priority queue.
    90  //
    91  // NOTE: This is part of the heap.Interface implementation.
    92  func (d *distanceHeap) Swap(i, j int) {
    93  	d.nodes[i], d.nodes[j] = d.nodes[j], d.nodes[i]
    94  	d.pubkeyIndices[d.nodes[i].node] = i
    95  	d.pubkeyIndices[d.nodes[j].node] = j
    96  }
    97  
    98  // Push pushes the passed item onto the priority queue.
    99  //
   100  // NOTE: This is part of the heap.Interface implementation.
   101  func (d *distanceHeap) Push(x interface{}) {
   102  	n := x.(*nodeWithDist)
   103  	d.nodes = append(d.nodes, n)
   104  	d.pubkeyIndices[n.node] = len(d.nodes) - 1
   105  }
   106  
   107  // Pop removes the highest priority item (according to Less) from the priority
   108  // queue and returns it.
   109  //
   110  // NOTE: This is part of the heap.Interface implementation.
   111  func (d *distanceHeap) Pop() interface{} {
   112  	n := len(d.nodes)
   113  	x := d.nodes[n-1]
   114  	d.nodes[n-1] = nil
   115  	d.nodes = d.nodes[0 : n-1]
   116  	delete(d.pubkeyIndices, x.node)
   117  	return x
   118  }
   119  
   120  // PushOrFix attempts to adjust the position of a given node in the heap.
   121  // If the vertex already exists in the heap, then we must call heap.Fix to
   122  // modify its position and reorder the heap. If the vertex does not already
   123  // exist in the heap, then it is pushed onto the heap. Otherwise, we will end
   124  // up performing more db lookups on the same node in the pathfinding algorithm.
   125  func (d *distanceHeap) PushOrFix(dist *nodeWithDist) {
   126  	index, ok := d.pubkeyIndices[dist.node]
   127  	if !ok {
   128  		heap.Push(d, dist)
   129  		return
   130  	}
   131  
   132  	// Change the value at the specified index.
   133  	d.nodes[index] = dist
   134  
   135  	// Call heap.Fix to reorder the heap.
   136  	heap.Fix(d, index)
   137  }