From bb3af4643f6a13c5dc8df46e5b586590f627b431 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Wed, 19 Feb 2025 07:58:22 -0300 Subject: [PATCH] graph/db: populate the graph cache in Start instead of during construction In this commit, we move the graph cache population logic out of the ChannelGraph constructor and into its Start method instead. --- docs/release-notes/release-notes-0.19.0.md | 1 + graph/db/graph.go | 88 ++++++++++++---------- 2 files changed, 51 insertions(+), 38 deletions(-) diff --git a/docs/release-notes/release-notes-0.19.0.md b/docs/release-notes/release-notes-0.19.0.md index 95f91e8a49..1af86dba3e 100644 --- a/docs/release-notes/release-notes-0.19.0.md +++ b/docs/release-notes/release-notes-0.19.0.md @@ -264,6 +264,7 @@ The underlying functionality between those two options remain the same. - [3](https://github.com/lightningnetwork/lnd/pull/9550) - [4](https://github.com/lightningnetwork/lnd/pull/9551) - [5](https://github.com/lightningnetwork/lnd/pull/9552) + - [6](https://github.com/lightningnetwork/lnd/pull/9555) * [Golang was updated to `v1.22.11`](https://github.com/lightningnetwork/lnd/pull/9462). diff --git a/graph/db/graph.go b/graph/db/graph.go index 94c571225e..f487593d42 100644 --- a/graph/db/graph.go +++ b/graph/db/graph.go @@ -2,6 +2,7 @@ package graphdb import ( "errors" + "fmt" "sync" "sync/atomic" "time" @@ -63,50 +64,18 @@ func NewChannelGraph(cfg *Config, options ...ChanGraphOption) (*ChannelGraph, return nil, err } - if !opts.useGraphCache { - return &ChannelGraph{ - KVStore: store, - quit: make(chan struct{}), - }, nil + g := &ChannelGraph{ + KVStore: store, + quit: make(chan struct{}), } // The graph cache can be turned off (e.g. for mobile users) for a // speed/memory usage tradeoff. - graphCache := NewGraphCache(opts.preAllocCacheNumNodes) - startTime := time.Now() - log.Debugf("Populating in-memory channel graph, this might take a " + - "while...") - - err = store.ForEachNodeCacheable(func(node route.Vertex, - features *lnwire.FeatureVector) error { - - graphCache.AddNodeFeatures(node, features) - - return nil - }) - if err != nil { - return nil, err + if opts.useGraphCache { + g.graphCache = NewGraphCache(opts.preAllocCacheNumNodes) } - err = store.ForEachChannel(func(info *models.ChannelEdgeInfo, - policy1, policy2 *models.ChannelEdgePolicy) error { - - graphCache.AddChannel(info, policy1, policy2) - - return nil - }) - if err != nil { - return nil, err - } - - log.Debugf("Finished populating in-memory channel graph (took %v, %s)", - time.Since(startTime), graphCache.Stats()) - - return &ChannelGraph{ - KVStore: store, - graphCache: graphCache, - quit: make(chan struct{}), - }, nil + return g, nil } // Start kicks off any goroutines required for the ChannelGraph to function. @@ -119,6 +88,13 @@ func (c *ChannelGraph) Start() error { log.Debugf("ChannelGraph starting") defer log.Debug("ChannelGraph started") + if c.graphCache != nil { + if err := c.populateCache(); err != nil { + return fmt.Errorf("could not populate the graph "+ + "cache: %w", err) + } + } + return nil } @@ -137,6 +113,42 @@ func (c *ChannelGraph) Stop() error { return nil } +// populateCache loads the entire channel graph into the in-memory graph cache. +// +// NOTE: This should only be called if the graphCache has been constructed. +func (c *ChannelGraph) populateCache() error { + startTime := time.Now() + log.Debugf("Populating in-memory channel graph, this might take a " + + "while...") + + err := c.KVStore.ForEachNodeCacheable(func(node route.Vertex, + features *lnwire.FeatureVector) error { + + c.graphCache.AddNodeFeatures(node, features) + + return nil + }) + if err != nil { + return err + } + + err = c.KVStore.ForEachChannel(func(info *models.ChannelEdgeInfo, + policy1, policy2 *models.ChannelEdgePolicy) error { + + c.graphCache.AddChannel(info, policy1, policy2) + + return nil + }) + if err != nil { + return err + } + + log.Debugf("Finished populating in-memory channel graph (took %v, %s)", + time.Since(startTime), c.graphCache.Stats()) + + return nil +} + // ForEachNodeDirectedChannel iterates through all channels of a given node, // executing the passed callback on the directed edge representing the channel // and its incoming policy. If the callback returns an error, then the iteration