@@ -9,6 +9,7 @@ use interface::{
9
9
} ;
10
10
use metrics_utils:: { MetricStatus , RpcBackfillerMetricsConfig } ;
11
11
use solana_sdk:: { pubkey:: Pubkey , signature:: Signature } ;
12
+ use tokio_util:: sync:: CancellationToken ;
12
13
use tracing:: info;
13
14
14
15
pub struct SignatureFetcher < T , SP , TI >
@@ -45,30 +46,43 @@ where
45
46
& self ,
46
47
program_id : Pubkey ,
47
48
rpc_retry_interval_millis : u64 ,
49
+ cancellation_token : CancellationToken ,
48
50
) -> Result < ( ) , StorageError > {
49
- let signature = self . data_layer . first_persisted_signature_for ( program_id) . await ?;
51
+ let signature = cancellation_token
52
+ . run_until_cancelled ( self . data_layer . first_persisted_signature_for ( program_id) )
53
+ . await
54
+ . unwrap_or ( Ok ( None ) ) ?;
50
55
if signature. is_none ( ) {
51
56
return Ok ( ( ) ) ;
52
57
}
53
58
let signature = signature. unwrap ( ) ;
54
59
info ! ( "Start fetching signatures..." ) ;
55
- let mut all_signatures = match self
56
- . rpc
57
- . get_signatures_by_address ( signature, program_id)
60
+ let mut all_signatures = cancellation_token
61
+ . run_until_cancelled ( async move {
62
+ match self
63
+ . rpc
64
+ . get_signatures_by_address ( signature, program_id)
65
+ . await
66
+ . map_err ( |e| StorageError :: Common ( e. to_string ( ) ) )
67
+ {
68
+ Ok ( all_signatures) => {
69
+ self . metrics . inc_fetch_signatures (
70
+ "get_signatures_by_address" ,
71
+ MetricStatus :: SUCCESS ,
72
+ ) ;
73
+ Ok ( all_signatures)
74
+ } ,
75
+ Err ( e) => {
76
+ self . metrics . inc_fetch_signatures (
77
+ "get_signatures_by_address" ,
78
+ MetricStatus :: FAILURE ,
79
+ ) ;
80
+ Err ( e)
81
+ } ,
82
+ }
83
+ } )
58
84
. await
59
- . map_err ( |e| StorageError :: Common ( e. to_string ( ) ) )
60
- {
61
- Ok ( all_signatures) => {
62
- self . metrics
63
- . inc_fetch_signatures ( "get_signatures_by_address" , MetricStatus :: SUCCESS ) ;
64
- all_signatures
65
- } ,
66
- Err ( e) => {
67
- self . metrics
68
- . inc_fetch_signatures ( "get_signatures_by_address" , MetricStatus :: FAILURE ) ;
69
- return Err ( e) ;
70
- } ,
71
- } ;
85
+ . unwrap_or_else ( || Ok ( vec ! [ ] ) ) ?;
72
86
73
87
if all_signatures. is_empty ( ) {
74
88
return Ok ( ( ) ) ;
@@ -85,14 +99,20 @@ where
85
99
all_signatures. sort_by ( |a, b| a. slot . cmp ( & b. slot ) ) ;
86
100
// we need to split the list into batches of BATCH_SIZE
87
101
88
- // todo: use Rust's chunks instead
89
- let mut batch_start = 0 ;
90
- while batch_start < all_signatures. len ( ) {
91
- let batch_end = std:: cmp:: min ( batch_start + BATCH_SIZE , all_signatures. len ( ) ) ;
92
- let batch = & all_signatures[ batch_start..batch_end] ;
93
- let missing_signatures =
94
- self . data_layer . missing_signatures ( program_id, batch. to_vec ( ) ) . await ?;
95
- batch_start = batch_end;
102
+ // this variable is required to account for the last batch potentially being smaller than
103
+ // the rest
104
+ let mut last_batch_index = 0 ;
105
+
106
+ for signatures in all_signatures. chunks ( BATCH_SIZE ) {
107
+ if cancellation_token. is_cancelled ( ) {
108
+ break ;
109
+ }
110
+ let missing_signatures = cancellation_token
111
+ . run_until_cancelled (
112
+ self . data_layer . missing_signatures ( program_id, signatures. to_vec ( ) ) ,
113
+ )
114
+ . await
115
+ . unwrap_or_else ( || Ok ( vec ! [ ] ) ) ?;
96
116
if missing_signatures. is_empty ( ) {
97
117
continue ;
98
118
}
@@ -101,12 +121,9 @@ where
101
121
missing_signatures. len( ) ,
102
122
program_id
103
123
) ;
104
-
105
124
let signatures: Vec < Signature > =
106
125
missing_signatures. iter ( ) . map ( |s| s. signature ) . collect ( ) ;
107
-
108
126
let tx_cnt = signatures. len ( ) ;
109
-
110
127
let counter = 0 ;
111
128
112
129
Self :: process_transactions (
@@ -125,24 +142,21 @@ where
125
142
126
143
let fake_key = SignatureWithSlot {
127
144
signature : Default :: default ( ) ,
128
- slot : all_signatures[ batch_end - 1 ] . slot ,
145
+ slot : all_signatures[ last_batch_index + missing_signatures . len ( ) - 1 ] . slot ,
129
146
} ;
130
147
info ! (
131
148
"Ingested {} transactions. Dropping signatures for program {} before slot {}." ,
132
149
tx_cnt, program_id, fake_key. slot
133
150
) ;
134
151
self . data_layer . drop_signatures_before ( program_id, fake_key) . await ?;
152
+ last_batch_index += missing_signatures. len ( ) ;
135
153
}
136
- let fake_key = SignatureWithSlot {
137
- signature : Default :: default ( ) ,
138
- slot : all_signatures[ all_signatures. len ( ) - 1 ] . slot ,
139
- } ;
140
154
141
155
info ! (
142
- "Finished fetching signatures for program {}. Dropping signatures before slot {}." ,
143
- program_id, fake_key. slot
156
+ "Finished fetching signatures for program {}. Dropped signatures before slot {}." ,
157
+ program_id,
158
+ all_signatures[ all_signatures. len( ) - 1 ] . slot
144
159
) ;
145
- self . data_layer . drop_signatures_before ( program_id, fake_key) . await ?;
146
160
Ok ( ( ) )
147
161
}
148
162
@@ -229,6 +243,7 @@ mod tests {
229
243
} ;
230
244
use metrics_utils:: RpcBackfillerMetricsConfig ;
231
245
use mockall:: predicate:: { self , eq} ;
246
+ use tokio_util:: sync:: CancellationToken ;
232
247
233
248
#[ tokio:: test]
234
249
async fn test_fetch_signatures_with_over_batch_limit_elements_should_complete_without_infinite_loop (
@@ -259,17 +274,12 @@ mod tests {
259
274
. with ( eq ( program_id) , predicate:: always ( ) )
260
275
. times ( 2 )
261
276
. returning ( move |_, _| Ok ( vec ! [ ] ) ) ;
262
- data_layer
263
- . expect_drop_signatures_before ( )
264
- . with ( eq ( program_id) , predicate:: always ( ) )
265
- . times ( 1 )
266
- . returning ( move |_, _| Ok ( ( ) ) ) ;
267
277
let fetcher = super :: SignatureFetcher :: new (
268
278
Arc :: new ( data_layer) ,
269
279
Arc :: new ( rpc) ,
270
280
Arc :: new ( ingester) ,
271
281
metrics,
272
282
) ;
273
- fetcher. fetch_signatures ( program_id, 0 ) . await . unwrap ( ) ;
283
+ fetcher. fetch_signatures ( program_id, 0 , CancellationToken :: new ( ) ) . await . unwrap ( ) ;
274
284
}
275
285
}
0 commit comments