diff --git a/config_builder.go b/config_builder.go index 9b33520fd..e18c0b2ff 100644 --- a/config_builder.go +++ b/config_builder.go @@ -1030,14 +1030,17 @@ func (d *DefaultDatabaseBuilder) BuildDatabase( graphdb.WithRejectCacheSize(cfg.Caches.RejectCacheSize), graphdb.WithChannelCacheSize(cfg.Caches.ChannelCacheSize), graphdb.WithBatchCommitInterval(cfg.DB.BatchCommitInterval), + } + + chanGraphOpts := []graphdb.ChanGraphOption{ graphdb.WithUseGraphCache(!cfg.DB.NoGraphCache), } // We want to pre-allocate the channel graph cache according to what we // expect for mainnet to speed up memory allocation. if cfg.ActiveNetParams.Name == chaincfg.MainNetParams.Name { - graphDBOptions = append( - graphDBOptions, graphdb.WithPreAllocCacheNumNodes( + chanGraphOpts = append( + chanGraphOpts, graphdb.WithPreAllocCacheNumNodes( graphdb.DefaultPreAllocCacheNumNodes, ), ) @@ -1046,7 +1049,7 @@ func (d *DefaultDatabaseBuilder) BuildDatabase( dbs.GraphDB, err = graphdb.NewChannelGraph(&graphdb.Config{ KVDB: databaseBackends.GraphDB, KVStoreOpts: graphDBOptions, - }) + }, chanGraphOpts...) if err != nil { cleanUp() diff --git a/docs/release-notes/release-notes-0.19.0.md b/docs/release-notes/release-notes-0.19.0.md index ff8752810..0ba2bb48d 100644 --- a/docs/release-notes/release-notes-0.19.0.md +++ b/docs/release-notes/release-notes-0.19.0.md @@ -323,6 +323,7 @@ The underlying functionality between those two options remain the same. - [Refactor to hide DB transactions](https://github.com/lightningnetwork/lnd/pull/9513) - Move the graph cache out of the graph CRUD layer: - [1](https://github.com/lightningnetwork/lnd/pull/9533) + - [2](https://github.com/lightningnetwork/lnd/pull/9545) * [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 b8140a9d6..c8f660bbb 100644 --- a/graph/db/graph.go +++ b/graph/db/graph.go @@ -1,6 +1,13 @@ package graphdb -import "github.com/lightningnetwork/lnd/kvdb" +import ( + "time" + + "github.com/lightningnetwork/lnd/graph/db/models" + "github.com/lightningnetwork/lnd/kvdb" + "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/routing/route" +) // Config is a struct that holds all the necessary dependencies for a // ChannelGraph. @@ -20,17 +27,67 @@ type Config struct { // KVStore. Upcoming commits will move the graph cache out of the KVStore and // into this layer so that the KVStore is only responsible for CRUD operations. type ChannelGraph struct { + graphCache *GraphCache + *KVStore } // NewChannelGraph creates a new ChannelGraph instance with the given backend. -func NewChannelGraph(cfg *Config) (*ChannelGraph, error) { +func NewChannelGraph(cfg *Config, options ...ChanGraphOption) (*ChannelGraph, + error) { + + opts := defaultChanGraphOptions() + for _, o := range options { + o(opts) + } + store, err := NewKVStore(cfg.KVDB, cfg.KVStoreOpts...) if err != nil { return nil, err } + if !opts.useGraphCache { + return &ChannelGraph{ + KVStore: store, + }, nil + } + + // 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 + } + + 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()) + + store.setGraphCache(graphCache) + return &ChannelGraph{ - KVStore: store, + KVStore: store, + graphCache: graphCache, }, nil } diff --git a/graph/db/graph_test.go b/graph/db/graph_test.go index e3681f4b0..8a6e3e82c 100644 --- a/graph/db/graph_test.go +++ b/graph/db/graph_test.go @@ -3924,6 +3924,7 @@ func TestGraphCacheForEachNodeChannel(t *testing.T) { // Unset the channel graph cache to simulate the user running with the // option turned off. graph.graphCache = nil + graph.KVStore.graphCache = nil node1, err := createTestVertex(graph.db) require.Nil(t, err) diff --git a/graph/db/kv_store.go b/graph/db/kv_store.go index 96babbec9..c54d08ca3 100644 --- a/graph/db/kv_store.go +++ b/graph/db/kv_store.go @@ -224,43 +224,18 @@ func NewKVStore(db kvdb.Backend, options ...KVStoreOptionModifier) (*KVStore, db, nil, opts.BatchCommitInterval, ) - // The graph cache can be turned off (e.g. for mobile users) for a - // speed/memory usage tradeoff. - if opts.UseGraphCache { - g.graphCache = NewGraphCache(opts.PreAllocCacheNumNodes) - startTime := time.Now() - log.Debugf("Populating in-memory channel graph, this might " + - "take a while...") - - err := g.ForEachNodeCacheable(func(node route.Vertex, - features *lnwire.FeatureVector) error { - - g.graphCache.AddNodeFeatures(node, features) - - return nil - }) - if err != nil { - return nil, err - } - - err = g.ForEachChannel(func(info *models.ChannelEdgeInfo, - policy1, policy2 *models.ChannelEdgePolicy) error { - - g.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), g.graphCache.Stats()) - } - return g, nil } +// setGraphCache sets the KVStore's graphCache. +// +// NOTE: this is temporary and will only be called from the ChannelGraph's +// constructor before the KVStore methods are available to be called. This will +// be removed once the graph cache is fully owned by the ChannelGraph. +func (c *KVStore) setGraphCache(cache *GraphCache) { + c.graphCache = cache +} + // channelMapKey is the key structure used for storing channel edge policies. type channelMapKey struct { nodeKey route.Vertex diff --git a/graph/db/options.go b/graph/db/options.go index a6cf2e909..7bff8637a 100644 --- a/graph/db/options.go +++ b/graph/db/options.go @@ -20,6 +20,47 @@ const ( DefaultPreAllocCacheNumNodes = 15000 ) +// chanGraphOptions holds parameters for tuning and customizing the +// ChannelGraph. +type chanGraphOptions struct { + // useGraphCache denotes whether the in-memory graph cache should be + // used or a fallback version that uses the underlying database for + // path finding. + useGraphCache bool + + // preAllocCacheNumNodes is the number of nodes we expect to be in the + // graph cache, so we can pre-allocate the map accordingly. + preAllocCacheNumNodes int +} + +// defaultChanGraphOptions returns a new chanGraphOptions instance populated +// with default values. +func defaultChanGraphOptions() *chanGraphOptions { + return &chanGraphOptions{ + useGraphCache: true, + preAllocCacheNumNodes: DefaultPreAllocCacheNumNodes, + } +} + +// ChanGraphOption describes the signature of a functional option that can be +// used to customize a ChannelGraph instance. +type ChanGraphOption func(*chanGraphOptions) + +// WithUseGraphCache sets whether the in-memory graph cache should be used. +func WithUseGraphCache(use bool) ChanGraphOption { + return func(o *chanGraphOptions) { + o.useGraphCache = use + } +} + +// WithPreAllocCacheNumNodes sets the number of nodes we expect to be in the +// graph cache, so we can pre-allocate the map accordingly. +func WithPreAllocCacheNumNodes(n int) ChanGraphOption { + return func(o *chanGraphOptions) { + o.preAllocCacheNumNodes = n + } +} + // KVStoreOptions holds parameters for tuning and customizing a graph.DB. type KVStoreOptions struct { // RejectCacheSize is the maximum number of rejectCacheEntries to hold @@ -34,15 +75,6 @@ type KVStoreOptions struct { // wait before attempting to commit a pending set of updates. BatchCommitInterval time.Duration - // PreAllocCacheNumNodes is the number of nodes we expect to be in the - // graph cache, so we can pre-allocate the map accordingly. - PreAllocCacheNumNodes int - - // UseGraphCache denotes whether the in-memory graph cache should be - // used or a fallback version that uses the underlying database for - // path finding. - UseGraphCache bool - // NoMigration specifies that underlying backend was opened in read-only // mode and migrations shouldn't be performed. This can be useful for // applications that use the channeldb package as a library. @@ -52,11 +84,9 @@ type KVStoreOptions struct { // DefaultOptions returns a KVStoreOptions populated with default values. func DefaultOptions() *KVStoreOptions { return &KVStoreOptions{ - RejectCacheSize: DefaultRejectCacheSize, - ChannelCacheSize: DefaultChannelCacheSize, - PreAllocCacheNumNodes: DefaultPreAllocCacheNumNodes, - UseGraphCache: true, - NoMigration: false, + RejectCacheSize: DefaultRejectCacheSize, + ChannelCacheSize: DefaultChannelCacheSize, + NoMigration: false, } } @@ -78,13 +108,6 @@ func WithChannelCacheSize(n int) KVStoreOptionModifier { } } -// WithPreAllocCacheNumNodes sets the PreAllocCacheNumNodes to n. -func WithPreAllocCacheNumNodes(n int) KVStoreOptionModifier { - return func(o *KVStoreOptions) { - o.PreAllocCacheNumNodes = n - } -} - // WithBatchCommitInterval sets the batch commit interval for the interval batch // schedulers. func WithBatchCommitInterval(interval time.Duration) KVStoreOptionModifier { @@ -92,10 +115,3 @@ func WithBatchCommitInterval(interval time.Duration) KVStoreOptionModifier { o.BatchCommitInterval = interval } } - -// WithUseGraphCache sets the UseGraphCache option to the given value. -func WithUseGraphCache(use bool) KVStoreOptionModifier { - return func(o *KVStoreOptions) { - o.UseGraphCache = use - } -} diff --git a/graph/notifications_test.go b/graph/notifications_test.go index 6846be15e..aab1d4137 100644 --- a/graph/notifications_test.go +++ b/graph/notifications_test.go @@ -1093,12 +1093,10 @@ func makeTestGraph(t *testing.T, useCache bool) (*graphdb.ChannelGraph, t.Cleanup(backendCleanup) - graph, err := graphdb.NewChannelGraph(&graphdb.Config{ - KVDB: backend, - KVStoreOpts: []graphdb.KVStoreOptionModifier{ - graphdb.WithUseGraphCache(useCache), - }, - }) + graph, err := graphdb.NewChannelGraph( + &graphdb.Config{KVDB: backend}, + graphdb.WithUseGraphCache(useCache), + ) if err != nil { return nil, nil, err } diff --git a/routing/pathfind_test.go b/routing/pathfind_test.go index 6aba44a4f..029383e0b 100644 --- a/routing/pathfind_test.go +++ b/routing/pathfind_test.go @@ -166,12 +166,10 @@ func makeTestGraph(t *testing.T, useCache bool) (*graphdb.ChannelGraph, t.Cleanup(backendCleanup) - graph, err := graphdb.NewChannelGraph(&graphdb.Config{ - KVDB: backend, - KVStoreOpts: []graphdb.KVStoreOptionModifier{ - graphdb.WithUseGraphCache(useCache), - }, - }) + graph, err := graphdb.NewChannelGraph( + &graphdb.Config{KVDB: backend}, + graphdb.WithUseGraphCache(useCache), + ) if err != nil { return nil, nil, err }