From 3e60a2363267405ada711033909f0b629260717f Mon Sep 17 00:00:00 2001 From: Juan Pablo Civile Date: Fri, 23 Aug 2019 12:27:02 -0300 Subject: [PATCH] routing: pre-allocate the distance map to an estimated node count Pre-sizing these structures avoids a lot of map resizing, which causes copies and rehashing of entries. We mostly know that the map won't exceed that size, and it doesn't affect memory usage in any significant way. --- routing/heap.go | 5 +++-- routing/heap_test.go | 2 +- routing/pathfind.go | 33 +++++++++++++++++++-------------- 3 files changed, 23 insertions(+), 17 deletions(-) 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.