@@ -20,9 +20,11 @@ import (
20
20
"github.com/btcsuite/btcd/chaincfg/chainhash"
21
21
"github.com/btcsuite/btcd/txscript"
22
22
"github.com/btcsuite/btcd/wire"
23
+ "github.com/btcsuite/btcwallet/walletdb"
23
24
"github.com/lightningnetwork/lnd/aliasmgr"
24
25
"github.com/lightningnetwork/lnd/batch"
25
26
"github.com/lightningnetwork/lnd/channeldb/models"
27
+ "github.com/lightningnetwork/lnd/fn"
26
28
"github.com/lightningnetwork/lnd/input"
27
29
"github.com/lightningnetwork/lnd/kvdb"
28
30
"github.com/lightningnetwork/lnd/lnwire"
@@ -185,9 +187,11 @@ type ChannelGraph struct {
185
187
chanCache * channelCache
186
188
graphCache * GraphCache
187
189
188
- graphCacheOnce sync.Once
189
190
graphCacheReady atomic.Bool
190
191
graphCacheErr error
192
+ updateQueue * fn.ConcurrentQueue [func (tx walletdb.ReadWriteTx ) error ]
193
+
194
+ cachePopulated sync.WaitGroup
191
195
192
196
chanScheduler batch.Scheduler
193
197
nodeScheduler batch.Scheduler
@@ -216,11 +220,14 @@ func NewChannelGraph(db kvdb.Backend, rejectCacheSize, chanCacheSize int,
216
220
g .nodeScheduler = batch .NewTimeScheduler (
217
221
db , nil , batchCommitInterval ,
218
222
)
223
+ g .updateQueue =
224
+ fn.NewConcurrentQueue [func (tx walletdb.ReadWriteTx ) error ](100 )
219
225
220
226
// The graph cache can be turned off (e.g. for mobile users) for a
221
227
// speed/memory usage tradeoff.
222
228
if useGraphCache {
223
229
g .graphCache = NewGraphCache (preAllocCacheNumNodes )
230
+ g .cachePopulated .Add (1 )
224
231
// Start populating the cache asynchronously
225
232
go g .populateGraphCache ()
226
233
}
@@ -235,6 +242,8 @@ type channelMapKey struct {
235
242
}
236
243
237
244
func (g * ChannelGraph ) populateGraphCache () {
245
+ defer g .cachePopulated .Done ()
246
+
238
247
startTime := time .Now ()
239
248
log .Debugf ("Populating in-memory channel graph, this might " +
240
249
"take a while..." )
@@ -263,27 +272,36 @@ func (g *ChannelGraph) populateGraphCache() {
263
272
return
264
273
}
265
274
266
- log .Debugf ("Finished populating in-memory channel graph (took " +
267
- "%v, %s)" , time .Since (startTime ), g .graphCache .Stats ())
275
+ if g .graphCache != nil {
276
+ log .Debugf ("Finished populating in-memory channel graph (took " +
277
+ "%v, %s)" , time .Since (startTime ), g .graphCache .Stats ())
278
+ }
268
279
280
+ // Set graphCache to be ready and process pending updates.
269
281
g .graphCacheReady .Store (true )
282
+ g .updateQueue .Start ()
283
+ go func () {
284
+ for update := range g .updateQueue .ChanOut () {
285
+ err := g .nodeScheduler .Execute (& batch.Request {
286
+ Update : func (tx kvdb.RwTx ) error {
287
+ return update (tx )
288
+ },
289
+ })
290
+ if err != nil {
291
+ fmt .Printf ("Failed to execute cache update " +
292
+ "function: %v\n " , err )
293
+ }
294
+ }
295
+ }()
270
296
}
271
297
272
298
func (c * ChannelGraph ) getGraphCache () (* GraphCache , error ) {
273
299
if c .graphCache == nil {
274
300
return nil , nil
275
301
}
276
302
277
- // Wait for up to 5 seconds for the cache to be ready
278
- timeout := time .After (5 * time .Second )
279
- for ! c .graphCacheReady .Load () {
280
- select {
281
- case <- timeout :
282
- return nil , fmt .Errorf ("timeout waiting for graph " +
283
- "cache to be ready" )
284
- case <- time .After (100 * time .Millisecond ):
285
- // Check again
286
- }
303
+ if ! c .graphCacheReady .Load () {
304
+ return nil , ErrGraphNotReady
287
305
}
288
306
289
307
if c .graphCacheErr != nil {
@@ -506,6 +524,7 @@ func (c *ChannelGraph) ForEachChannel(cb func(*models.ChannelEdgeInfo,
506
524
func (c * ChannelGraph ) ForEachNodeDirectedChannel (tx kvdb.RTx ,
507
525
node route.Vertex , cb func (channel * DirectedChannel ) error ) error {
508
526
527
+ // If graphCache is fully populated, use it.
509
528
graphCache , err := c .getGraphCache ()
510
529
if err == nil && graphCache != nil {
511
530
return graphCache .ForEachChannel (node , cb )
@@ -564,6 +583,7 @@ func (c *ChannelGraph) ForEachNodeDirectedChannel(tx kvdb.RTx,
564
583
func (c * ChannelGraph ) FetchNodeFeatures (
565
584
node route.Vertex ) (* lnwire.FeatureVector , error ) {
566
585
586
+ // If graphCache is fully populated, use it.
567
587
graphCache , err := c .getGraphCache ()
568
588
if err == nil && graphCache != nil {
569
589
return graphCache .GetFeatures (node ), nil
@@ -875,17 +895,6 @@ func (c *ChannelGraph) AddLightningNode(node *LightningNode,
875
895
876
896
r := & batch.Request {
877
897
Update : func (tx kvdb.RwTx ) error {
878
- graphCache , err := c .getGraphCache ()
879
- if err == nil && graphCache != nil {
880
- cNode := newGraphCacheNode (
881
- node .PubKeyBytes , node .Features ,
882
- )
883
- err := graphCache .AddNode (tx , cNode )
884
- if err != nil {
885
- return err
886
- }
887
- }
888
-
889
898
return addLightningNode (tx , node )
890
899
},
891
900
}
@@ -894,6 +903,31 @@ func (c *ChannelGraph) AddLightningNode(node *LightningNode,
894
903
f (r )
895
904
}
896
905
906
+ updateCache := func (tx kvdb.RwTx ) error {
907
+ graphCache , err := c .getGraphCache ()
908
+ if err == nil && graphCache != nil {
909
+ cNode := newGraphCacheNode (node .PubKeyBytes , node .Features )
910
+ err := graphCache .AddNode (tx , cNode )
911
+ if err != nil {
912
+ return err
913
+ }
914
+ }
915
+ return nil
916
+ }
917
+
918
+ // If the graph cache is not ready, queue the cache update
919
+ if ! c .graphCacheReady .Load () {
920
+ c .updateQueue .ChanIn () <- updateCache
921
+ } else {
922
+ // If the cache is ready, execute the cache update immediately
923
+ err := c .nodeScheduler .Execute (& batch.Request {
924
+ Update : updateCache ,
925
+ })
926
+ if err != nil {
927
+ return err
928
+ }
929
+ }
930
+
897
931
return c .nodeScheduler .Execute (r )
898
932
}
899
933
0 commit comments