diff --git a/routing/heap.go b/routing/heap.go index 1cbbc5e5..a20f1d57 100644 --- a/routing/heap.go +++ b/routing/heap.go @@ -50,9 +50,10 @@ type distanceHeap struct { // newDistanceHeap initializes a new distance heap. This is required because // we must initialize the pubkeyIndices map for path-finding optimizations. -func newDistanceHeap() distanceHeap { +func newDistanceHeap(numNodes int) distanceHeap { distHeap := distanceHeap{ - pubkeyIndices: make(map[route.Vertex]int), + pubkeyIndices: make(map[route.Vertex]int, numNodes), + nodes: make([]nodeWithDist, 0, numNodes), } return distHeap diff --git a/routing/heap_test.go b/routing/heap_test.go index 4214e965..178bd9f1 100644 --- a/routing/heap_test.go +++ b/routing/heap_test.go @@ -17,7 +17,7 @@ func TestHeapOrdering(t *testing.T) { // First, create a blank heap, we'll use this to push on randomly // generated items. - nodeHeap := newDistanceHeap() + nodeHeap := newDistanceHeap(0) prand.Seed(1) diff --git a/routing/pathfind.go b/routing/pathfind.go index cb753941..e3e457cf 100644 --- a/routing/pathfind.go +++ b/routing/pathfind.go @@ -37,6 +37,11 @@ const ( // some effect with smaller time lock values. The value may need // tweaking and/or be made configurable in the future. RiskFactorBillionths = 15 + + // estimatedNodeCount is used to preallocate the path finding structures + // to avoid resizing and copies. It should be number on the same order as + // the number of active nodes in the network. + estimatedNodeCount = 10000 ) // pathFinder defines the interface of a path finding algorithm. @@ -320,14 +325,6 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig, defer tx.Rollback() } - // First we'll initialize an empty heap which'll help us to quickly - // locate the next edge we should visit next during our graph - // traversal. - nodeHeap := newDistanceHeap() - - // Holds the current best distance for a given node. - distance := make(map[route.Vertex]nodeWithDist) - if r.DestPayloadTLV { // Check if the target has TLV enabled @@ -352,6 +349,19 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig, } } + // First we'll initialize an empty heap which'll help us to quickly + // locate the next edge we should visit next during our graph + // traversal. + nodeHeap := newDistanceHeap(estimatedNodeCount) + + // Holds the current best distance for a given node. + distance := make(map[route.Vertex]nodeWithDist, estimatedNodeCount) + + // We'll use this map as a series of "next" hop pointers. So to get + // from `Vertex` to the target node, we'll take the edge that it's + // mapped to within `next`. + next := make(map[route.Vertex]*channeldb.ChannelEdgePolicy, estimatedNodeCount) + additionalEdgesWithSrc := make(map[route.Vertex][]*edgePolicyWithSource) for vertex, outgoingEdgePolicies := range g.additionalEdges { @@ -385,11 +395,6 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig, probability: 1, } - // We'll use this map as a series of "next" hop pointers. So to get - // from `Vertex` to the target node, we'll take the edge that it's - // mapped to within `next`. - next := make(map[route.Vertex]*channeldb.ChannelEdgePolicy) - // processEdge is a helper closure that will be used to make sure edges // satisfy our specific requirements. processEdge := func(fromVertex route.Vertex, bandwidth lnwire.MilliSatoshi, @@ -659,7 +664,7 @@ func findPath(g *graphParams, r *RestrictParams, cfg *PathFindingConfig, // Use the nextHop map to unravel the forward path from source to // target. - pathEdges := make([]*channeldb.ChannelEdgePolicy, 0, len(next)) + var pathEdges []*channeldb.ChannelEdgePolicy currentNode := source for currentNode != target { // TODO(roasbeef): assumes no cycles // Determine the next hop forward using the next map.