@@ -185,12 +185,13 @@ type ChannelGraph struct {
185
185
chanCache * channelCache
186
186
graphCache * GraphCache
187
187
188
- graphCacheOnce sync.Once
189
188
graphCacheReady atomic.Bool
190
189
graphCacheErr error
191
190
192
191
chanScheduler batch.Scheduler
193
192
nodeScheduler batch.Scheduler
193
+
194
+ writeOps chan func () error
194
195
}
195
196
196
197
// NewChannelGraph allocates a new ChannelGraph backed by a DB instance. The
@@ -216,6 +217,7 @@ func NewChannelGraph(db kvdb.Backend, rejectCacheSize, chanCacheSize int,
216
217
g .nodeScheduler = batch .NewTimeScheduler (
217
218
db , nil , batchCommitInterval ,
218
219
)
220
+ g .writeOps = make (chan func () error , 100 )
219
221
220
222
// The graph cache can be turned off (e.g. for mobile users) for a
221
223
// speed/memory usage tradeoff.
@@ -224,6 +226,7 @@ func NewChannelGraph(db kvdb.Backend, rejectCacheSize, chanCacheSize int,
224
226
// Start populating the cache asynchronously
225
227
go g .populateGraphCache ()
226
228
}
229
+ g .startWorker ()
227
230
228
231
return g , nil
229
232
}
@@ -234,6 +237,29 @@ type channelMapKey struct {
234
237
chanID [8 ]byte
235
238
}
236
239
240
+ func (c * ChannelGraph ) startWorker () {
241
+ go func () {
242
+ for op := range c .writeOps {
243
+ if err := op (); err != nil {
244
+ log .Warnf ("Error executing operation: %v" , err )
245
+ }
246
+ }
247
+ }()
248
+ }
249
+
250
+ func (c * ChannelGraph ) enqueueWriteOperation (op func () error ) {
251
+ // Send the operation to the channel; non-blocking if the buffer isn't full
252
+ select {
253
+ case c .writeOps <- op :
254
+ // Operation enqueued successfully
255
+ default :
256
+ // Handle the case where the channel is full
257
+ // Could log an error, block until space is available, or drop the operation
258
+ // For example, to block until space is available, remove the select and default case
259
+ log .Warn ("writeOps queue is full, operation not enqueued" )
260
+ }
261
+ }
262
+
237
263
func (g * ChannelGraph ) populateGraphCache () {
238
264
startTime := time .Now ()
239
265
log .Debugf ("Populating in-memory channel graph, this might " +
@@ -274,16 +300,11 @@ func (c *ChannelGraph) getGraphCache() (*GraphCache, error) {
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
+ // Check if graph cache is ready without waiting
304
+ if ! c .graphCacheReady .Load () {
305
+ // Return an error or a special indicator that cache is not ready
306
+ // Caller should handle this case appropriately, maybe by queuing write operations
307
+ return nil , ErrGraphCacheNotReady
287
308
}
288
309
289
310
if c .graphCacheErr != nil {
@@ -876,7 +897,21 @@ func (c *ChannelGraph) AddLightningNode(node *LightningNode,
876
897
r := & batch.Request {
877
898
Update : func (tx kvdb.RwTx ) error {
878
899
graphCache , err := c .getGraphCache ()
879
- if err == nil && graphCache != nil {
900
+ if err != nil {
901
+ if err == ErrGraphCacheNotReady {
902
+ // Queue this update function
903
+ c .enqueueWriteOperation (func () error {
904
+ return c .AddLightningNode (
905
+ node ,
906
+ op ... ,
907
+ )
908
+ })
909
+ return nil
910
+ }
911
+ return err
912
+ }
913
+
914
+ if graphCache != nil {
880
915
cNode := newGraphCacheNode (
881
916
node .PubKeyBytes , node .Features ,
882
917
)
@@ -965,7 +1000,18 @@ func (c *ChannelGraph) DeleteLightningNode(nodePub route.Vertex) error {
965
1000
}
966
1001
967
1002
graphCache , err := c .getGraphCache ()
968
- if err == nil && graphCache != nil {
1003
+ if err != nil {
1004
+ if err == ErrGraphCacheNotReady {
1005
+ // Queue this delete function
1006
+ c .enqueueWriteOperation (func () error {
1007
+ return c .DeleteLightningNode (nodePub )
1008
+ })
1009
+ return nil
1010
+ }
1011
+ return err
1012
+ }
1013
+
1014
+ if graphCache != nil {
969
1015
graphCache .RemoveNode (nodePub )
970
1016
}
971
1017
@@ -1097,7 +1143,18 @@ func (c *ChannelGraph) addChannelEdge(tx kvdb.RwTx,
1097
1143
}
1098
1144
1099
1145
graphCache , err := c .getGraphCache ()
1100
- if err == nil && graphCache != nil {
1146
+ if err != nil {
1147
+ if err == ErrGraphCacheNotReady {
1148
+ // Queue this function
1149
+ c .enqueueWriteOperation (func () error {
1150
+ return c .addChannelEdge (tx , edge )
1151
+ })
1152
+ return nil
1153
+ }
1154
+ return err
1155
+ }
1156
+
1157
+ if graphCache != nil {
1101
1158
graphCache .AddChannel (edge , nil , nil )
1102
1159
}
1103
1160
@@ -1301,7 +1358,18 @@ func (c *ChannelGraph) UpdateChannelEdge(edge *models.ChannelEdgeInfo) error {
1301
1358
}
1302
1359
1303
1360
graphCache , err := c .getGraphCache ()
1304
- if err == nil && graphCache != nil {
1361
+ if err != nil {
1362
+ if err == ErrGraphCacheNotReady {
1363
+ // Queue this update function
1364
+ c .enqueueWriteOperation (func () error {
1365
+ return c .UpdateChannelEdge (edge )
1366
+ })
1367
+ return nil
1368
+ }
1369
+ return err
1370
+ }
1371
+
1372
+ if graphCache != nil {
1305
1373
graphCache .UpdateChannel (edge )
1306
1374
}
1307
1375
@@ -1536,6 +1604,18 @@ func (c *ChannelGraph) pruneGraphNodes(nodes kvdb.RwBucket,
1536
1604
return err
1537
1605
}
1538
1606
1607
+ graphCache , err := c .getGraphCache ()
1608
+ if err != nil {
1609
+ if err == ErrGraphCacheNotReady {
1610
+ // Queue this prune operation
1611
+ c .enqueueWriteOperation (func () error {
1612
+ return c .pruneGraphNodes (nodes , edgeIndex )
1613
+ })
1614
+ return nil
1615
+ }
1616
+ return err
1617
+ }
1618
+
1539
1619
// Finally, we'll make a second pass over the set of nodes, and delete
1540
1620
// any nodes that have a ref count of zero.
1541
1621
var numNodesPruned int
@@ -1547,8 +1627,7 @@ func (c *ChannelGraph) pruneGraphNodes(nodes kvdb.RwBucket,
1547
1627
continue
1548
1628
}
1549
1629
1550
- graphCache , err := c .getGraphCache ()
1551
- if err == nil && graphCache != nil {
1630
+ if graphCache != nil {
1552
1631
graphCache .RemoveNode (nodePubKey )
1553
1632
}
1554
1633
@@ -2580,7 +2659,18 @@ func (c *ChannelGraph) delChannelEdgeUnsafe(edges, edgeIndex, chanIndex,
2580
2659
}
2581
2660
2582
2661
graphCache , err := c .getGraphCache ()
2583
- if err == nil && graphCache != nil {
2662
+ if err != nil {
2663
+ if err == ErrGraphCacheNotReady {
2664
+ // Queue this delete function
2665
+ c .enqueueWriteOperation (func () error {
2666
+ return c .delChannelEdgeUnsafe (edges , edgeIndex , chanIndex , zombieIndex , chanID , isZombie , strictZombie )
2667
+ })
2668
+ return nil
2669
+ }
2670
+ return err
2671
+ }
2672
+
2673
+ if graphCache != nil {
2584
2674
graphCache .RemoveChannel (
2585
2675
edgeInfo .NodeKey1Bytes , edgeInfo .NodeKey2Bytes ,
2586
2676
edgeInfo .ChannelID ,
@@ -2719,7 +2809,7 @@ func (c *ChannelGraph) UpdateEdgePolicy(edge *models.ChannelEdgePolicy,
2719
2809
Update : func (tx kvdb.RwTx ) error {
2720
2810
var err error
2721
2811
isUpdate1 , err = updateEdgePolicy (
2722
- tx , edge , c . graphCache ,
2812
+ tx , edge , c ,
2723
2813
)
2724
2814
2725
2815
// Silence ErrEdgeNotFound so that the batch can
@@ -2786,7 +2876,7 @@ func (c *ChannelGraph) updateEdgeCache(e *models.ChannelEdgePolicy,
2786
2876
// true if the updated policy belongs to node1, and false if the policy belonged
2787
2877
// to node2.
2788
2878
func updateEdgePolicy (tx kvdb.RwTx , edge * models.ChannelEdgePolicy ,
2789
- graphCache * GraphCache ) (bool , error ) {
2879
+ c * ChannelGraph ) (bool , error ) {
2790
2880
2791
2881
edges := tx .ReadWriteBucket (edgeBucket )
2792
2882
if edges == nil {
@@ -2837,7 +2927,25 @@ func updateEdgePolicy(tx kvdb.RwTx, edge *models.ChannelEdgePolicy,
2837
2927
copy (fromNodePubKey [:], fromNode )
2838
2928
copy (toNodePubKey [:], toNode )
2839
2929
2930
+ graphCache , err := c .getGraphCache ()
2931
+ if err != nil {
2932
+ if err == ErrGraphCacheNotReady {
2933
+ // Queue this update function
2934
+ c .enqueueWriteOperation (func () error {
2935
+ _ , err := updateEdgePolicy (tx , edge , c )
2936
+ return err
2937
+ })
2938
+ return false , nil
2939
+ }
2940
+ return false , err
2941
+ }
2942
+
2840
2943
if graphCache != nil {
2944
+ var fromNodePubKey route.Vertex
2945
+ var toNodePubKey route.Vertex
2946
+ copy (fromNodePubKey [:], fromNode )
2947
+ copy (toNodePubKey [:], toNode )
2948
+
2841
2949
graphCache .UpdatePolicy (
2842
2950
edge , fromNodePubKey , toNodePubKey , isUpdate1 ,
2843
2951
)
@@ -3713,7 +3821,18 @@ func (c *ChannelGraph) MarkEdgeZombie(chanID uint64,
3713
3821
}
3714
3822
3715
3823
graphCache , err := c .getGraphCache ()
3716
- if err == nil && graphCache != nil {
3824
+ if err != nil {
3825
+ if err == ErrGraphCacheNotReady {
3826
+ // Queue this function
3827
+ c .enqueueWriteOperation (func () error {
3828
+ return c .MarkEdgeZombie (chanID , pubKey1 , pubKey2 )
3829
+ })
3830
+ return nil
3831
+ }
3832
+ return err
3833
+ }
3834
+
3835
+ if graphCache != nil {
3717
3836
graphCache .RemoveChannel (pubKey1 , pubKey2 , chanID )
3718
3837
}
3719
3838
@@ -3798,7 +3917,19 @@ func (c *ChannelGraph) markEdgeLiveUnsafe(tx kvdb.RwTx, chanID uint64) error {
3798
3917
// We need to add the channel back into our graph cache, otherwise we
3799
3918
// won't use it for path finding.
3800
3919
graphCache , err := c .getGraphCache ()
3801
- if err == nil && graphCache != nil {
3920
+ if err != nil {
3921
+ if err == ErrGraphCacheNotReady {
3922
+ // Queue the operation to add the channel back.
3923
+ c .enqueueWriteOperation (func () error {
3924
+ return c .markEdgeLiveUnsafe (tx , chanID )
3925
+ })
3926
+ return nil
3927
+ }
3928
+ return err
3929
+ }
3930
+
3931
+ if graphCache != nil {
3932
+ // Fetch the channel info to add back into the graph cache.
3802
3933
edgeInfos , err := c .fetchChanInfos (tx , []uint64 {chanID })
3803
3934
if err != nil {
3804
3935
return err
0 commit comments