@@ -25,11 +25,12 @@ use lightning::ln::msgs::DecodeError;
2525use lightning:: routing:: gossip:: NetworkGraph ;
2626use lightning:: routing:: scoring:: { ProbabilisticScorer , ProbabilisticScoringDecayParameters } ;
2727use lightning:: util:: persist:: {
28- KVSTORE_NAMESPACE_KEY_ALPHABET , KVSTORE_NAMESPACE_KEY_MAX_LEN , NETWORK_GRAPH_PERSISTENCE_KEY ,
29- NETWORK_GRAPH_PERSISTENCE_PRIMARY_NAMESPACE , NETWORK_GRAPH_PERSISTENCE_SECONDARY_NAMESPACE ,
30- OUTPUT_SWEEPER_PERSISTENCE_KEY , OUTPUT_SWEEPER_PERSISTENCE_PRIMARY_NAMESPACE ,
31- OUTPUT_SWEEPER_PERSISTENCE_SECONDARY_NAMESPACE , SCORER_PERSISTENCE_KEY ,
32- SCORER_PERSISTENCE_PRIMARY_NAMESPACE , SCORER_PERSISTENCE_SECONDARY_NAMESPACE ,
28+ KVSTORE_NAMESPACE_KEY_ALPHABET , KVSTORE_NAMESPACE_KEY_MAX_LEN ,
29+ NETWORK_GRAPH_PERSISTENCE_KEY , NETWORK_GRAPH_PERSISTENCE_PRIMARY_NAMESPACE ,
30+ NETWORK_GRAPH_PERSISTENCE_SECONDARY_NAMESPACE , OUTPUT_SWEEPER_PERSISTENCE_KEY ,
31+ OUTPUT_SWEEPER_PERSISTENCE_PRIMARY_NAMESPACE , OUTPUT_SWEEPER_PERSISTENCE_SECONDARY_NAMESPACE ,
32+ SCORER_PERSISTENCE_KEY , SCORER_PERSISTENCE_PRIMARY_NAMESPACE ,
33+ SCORER_PERSISTENCE_SECONDARY_NAMESPACE ,
3334} ;
3435use lightning:: util:: ser:: { Readable , ReadableArgs , Writeable } ;
3536use lightning:: util:: string:: PrintableString ;
@@ -203,33 +204,59 @@ where
203204}
204205
205206/// Read previously persisted payments information from the store.
206- pub ( crate ) fn read_payments < L : Deref > (
207+ pub ( crate ) fn read_payments < L : Deref + Clone + Send > (
207208 kv_store : Arc < DynStore > , logger : L ,
208209) -> Result < Vec < PaymentDetails > , std:: io:: Error >
209210where
210211 L :: Target : LdkLogger ,
211212{
212- let mut res = Vec :: new ( ) ;
213-
214- for stored_key in kv_store. list (
213+ let keys = kv_store. list (
215214 PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE ,
216215 PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE ,
217- ) ? {
218- let mut reader = Cursor :: new ( kv_store. read (
219- PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE ,
220- PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE ,
221- & stored_key,
222- ) ?) ;
223- let payment = PaymentDetails :: read ( & mut reader) . map_err ( |e| {
224- log_error ! ( logger, "Failed to deserialize PaymentDetails: {}" , e) ;
225- std:: io:: Error :: new (
226- std:: io:: ErrorKind :: InvalidData ,
227- "Failed to deserialize PaymentDetails" ,
228- )
229- } ) ?;
230- res. push ( payment) ;
231- }
232- Ok ( res)
216+ ) ?;
217+
218+ // Read all payments in parallel using scoped threads.
219+ // This significantly improves performance for network-backed stores like VSS,
220+ // where sequential reads would incur per-key network latency.
221+ let results: Vec < Result < PaymentDetails , std:: io:: Error > > = std:: thread:: scope ( |s| {
222+ let handles: Vec < _ > = keys
223+ . iter ( )
224+ . map ( |key| {
225+ let kv_store = Arc :: clone ( & kv_store) ;
226+ let logger = logger. clone ( ) ;
227+ s. spawn ( move || {
228+ let mut reader = Cursor :: new ( kv_store. read (
229+ PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE ,
230+ PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE ,
231+ key,
232+ ) ?) ;
233+ PaymentDetails :: read ( & mut reader) . map_err ( |e| {
234+ log_error ! ( logger, "Failed to deserialize PaymentDetails: {}" , e) ;
235+ std:: io:: Error :: new (
236+ std:: io:: ErrorKind :: InvalidData ,
237+ "Failed to deserialize PaymentDetails" ,
238+ )
239+ } )
240+ } )
241+ } )
242+ . collect ( ) ;
243+
244+ handles
245+ . into_iter ( )
246+ . map ( |h| {
247+ h. join ( )
248+ . map_err ( |_| {
249+ std:: io:: Error :: new (
250+ std:: io:: ErrorKind :: Other ,
251+ "Thread panicked while reading payment" ,
252+ )
253+ } )
254+ . and_then ( |r| r)
255+ } )
256+ . collect ( )
257+ } ) ;
258+
259+ results. into_iter ( ) . collect ( )
233260}
234261
235262/// Read `OutputSweeper` state from the store.
0 commit comments