graph/db: let ChannelGraph init the graphCache

In this commit, we let the ChannelGraph be responsible for populating
the graphCache and then passing it to the KVStore. This is a first step
in moving the graphCache completely out of the KVStore layer.
This commit is contained in:
Elle Mouton committed 2025-03-24 15:05:46 +02:00
1 parent 00432e46f3
commit 88398e3dd9
8 files changed
+129 -80

No files matched your search

+6 -3
View File
@@ -1030,14 +1030,17 @@ func (d *DefaultDatabaseBuilder) BuildDatabase(
graphdb.WithRejectCacheSize(cfg.Caches.RejectCacheSize), graphdb.WithRejectCacheSize(cfg.Caches.RejectCacheSize),
graphdb.WithChannelCacheSize(cfg.Caches.ChannelCacheSize), graphdb.WithChannelCacheSize(cfg.Caches.ChannelCacheSize),
graphdb.WithBatchCommitInterval(cfg.DB.BatchCommitInterval), graphdb.WithBatchCommitInterval(cfg.DB.BatchCommitInterval),
}
chanGraphOpts := []graphdb.ChanGraphOption{
graphdb.WithUseGraphCache(!cfg.DB.NoGraphCache), graphdb.WithUseGraphCache(!cfg.DB.NoGraphCache),
} }
// We want to pre-allocate the channel graph cache according to what we // We want to pre-allocate the channel graph cache according to what we
// expect for mainnet to speed up memory allocation. // expect for mainnet to speed up memory allocation.
if cfg.ActiveNetParams.Name == chaincfg.MainNetParams.Name { if cfg.ActiveNetParams.Name == chaincfg.MainNetParams.Name {
graphDBOptions = append( chanGraphOpts = append(
graphDBOptions, graphdb.WithPreAllocCacheNumNodes( chanGraphOpts, graphdb.WithPreAllocCacheNumNodes(
graphdb.DefaultPreAllocCacheNumNodes, graphdb.DefaultPreAllocCacheNumNodes,
), ),
) )
@@ -1046,7 +1049,7 @@ func (d *DefaultDatabaseBuilder) BuildDatabase(
dbs.GraphDB, err = graphdb.NewChannelGraph(&graphdb.Config{ dbs.GraphDB, err = graphdb.NewChannelGraph(&graphdb.Config{
KVDB: databaseBackends.GraphDB, KVDB: databaseBackends.GraphDB,
KVStoreOpts: graphDBOptions, KVStoreOpts: graphDBOptions,
}) }, chanGraphOpts...)
if err != nil { if err != nil {
cleanUp() cleanUp()
@@ -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) - [Refactor to hide DB transactions](https://github.com/lightningnetwork/lnd/pull/9513)
- Move the graph cache out of the graph CRUD layer: - Move the graph cache out of the graph CRUD layer:
- [1](https://github.com/lightningnetwork/lnd/pull/9533) - [1](https://github.com/lightningnetwork/lnd/pull/9533)
- [2](https://github.com/lightningnetwork/lnd/pull/9545)
* [Golang was updated to * [Golang was updated to
`v1.22.11`](https://github.com/lightningnetwork/lnd/pull/9462). `v1.22.11`](https://github.com/lightningnetwork/lnd/pull/9462).
+60 -3
View File
@@ -1,6 +1,13 @@
package graphdb 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 // Config is a struct that holds all the necessary dependencies for a
// ChannelGraph. // ChannelGraph.
@@ -20,17 +27,67 @@ type Config struct {
// KVStore. Upcoming commits will move the graph cache out of the KVStore and // 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. // into this layer so that the KVStore is only responsible for CRUD operations.
type ChannelGraph struct { type ChannelGraph struct {
graphCache *GraphCache
*KVStore *KVStore
} }
// NewChannelGraph creates a new ChannelGraph instance with the given backend. // 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...) store, err := NewKVStore(cfg.KVDB, cfg.KVStoreOpts...)
if err != nil { if err != nil {
return nil, err 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{ return &ChannelGraph{
KVStore: store, KVStore: store,
graphCache: graphCache,
}, nil }, nil
} }
+1
View File
@@ -3924,6 +3924,7 @@ func TestGraphCacheForEachNodeChannel(t *testing.T) {
// Unset the channel graph cache to simulate the user running with the // Unset the channel graph cache to simulate the user running with the
// option turned off. // option turned off.
graph.graphCache = nil graph.graphCache = nil
graph.KVStore.graphCache = nil
node1, err := createTestVertex(graph.db) node1, err := createTestVertex(graph.db)
require.Nil(t, err) require.Nil(t, err)
+9 -34
View File
@@ -224,43 +224,18 @@ func NewKVStore(db kvdb.Backend, options ...KVStoreOptionModifier) (*KVStore,
db, nil, opts.BatchCommitInterval, 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 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. // channelMapKey is the key structure used for storing channel edge policies.
type channelMapKey struct { type channelMapKey struct {
nodeKey route.Vertex nodeKey route.Vertex
+44 -28
View File
@@ -20,6 +20,47 @@ const (
DefaultPreAllocCacheNumNodes = 15000 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. // KVStoreOptions holds parameters for tuning and customizing a graph.DB.
type KVStoreOptions struct { type KVStoreOptions struct {
// RejectCacheSize is the maximum number of rejectCacheEntries to hold // 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. // wait before attempting to commit a pending set of updates.
BatchCommitInterval time.Duration 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 // NoMigration specifies that underlying backend was opened in read-only
// mode and migrations shouldn't be performed. This can be useful for // mode and migrations shouldn't be performed. This can be useful for
// applications that use the channeldb package as a library. // applications that use the channeldb package as a library.
@@ -52,11 +84,9 @@ type KVStoreOptions struct {
// DefaultOptions returns a KVStoreOptions populated with default values. // DefaultOptions returns a KVStoreOptions populated with default values.
func DefaultOptions() *KVStoreOptions { func DefaultOptions() *KVStoreOptions {
return &KVStoreOptions{ return &KVStoreOptions{
RejectCacheSize: DefaultRejectCacheSize, RejectCacheSize: DefaultRejectCacheSize,
ChannelCacheSize: DefaultChannelCacheSize, ChannelCacheSize: DefaultChannelCacheSize,
PreAllocCacheNumNodes: DefaultPreAllocCacheNumNodes, NoMigration: false,
UseGraphCache: true,
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 // WithBatchCommitInterval sets the batch commit interval for the interval batch
// schedulers. // schedulers.
func WithBatchCommitInterval(interval time.Duration) KVStoreOptionModifier { func WithBatchCommitInterval(interval time.Duration) KVStoreOptionModifier {
@@ -92,10 +115,3 @@ func WithBatchCommitInterval(interval time.Duration) KVStoreOptionModifier {
o.BatchCommitInterval = interval o.BatchCommitInterval = interval
} }
} }
// WithUseGraphCache sets the UseGraphCache option to the given value.
func WithUseGraphCache(use bool) KVStoreOptionModifier {
return func(o *KVStoreOptions) {
o.UseGraphCache = use
}
}
+4 -6
View File
@@ -1093,12 +1093,10 @@ func makeTestGraph(t *testing.T, useCache bool) (*graphdb.ChannelGraph,
t.Cleanup(backendCleanup) t.Cleanup(backendCleanup)
graph, err := graphdb.NewChannelGraph(&graphdb.Config{ graph, err := graphdb.NewChannelGraph(
KVDB: backend, &graphdb.Config{KVDB: backend},
KVStoreOpts: []graphdb.KVStoreOptionModifier{ graphdb.WithUseGraphCache(useCache),
graphdb.WithUseGraphCache(useCache), )
},
})
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
+4 -6
View File
@@ -166,12 +166,10 @@ func makeTestGraph(t *testing.T, useCache bool) (*graphdb.ChannelGraph,
t.Cleanup(backendCleanup) t.Cleanup(backendCleanup)
graph, err := graphdb.NewChannelGraph(&graphdb.Config{ graph, err := graphdb.NewChannelGraph(
KVDB: backend, &graphdb.Config{KVDB: backend},
KVStoreOpts: []graphdb.KVStoreOptionModifier{ graphdb.WithUseGraphCache(useCache),
graphdb.WithUseGraphCache(useCache), )
},
})
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }