Line data Source code
1 : #include "fd_acc_mgr.h"
2 : #include "../../ballet/base58/fd_base58.h"
3 : #include "context/fd_exec_epoch_ctx.h"
4 : #include "context/fd_exec_slot_ctx.h"
5 : #include "fd_rent_lists.h"
6 : #include "fd_rocksdb.h"
7 : #include "sysvar/fd_sysvar_rent.h"
8 : #include "fd_system_ids.h"
9 : #include <assert.h>
10 :
11 : fd_acc_mgr_t *
12 : fd_acc_mgr_new( void * mem,
13 407862 : fd_funk_t * funk ) {
14 :
15 407862 : if( FD_UNLIKELY( !mem ) ) {
16 0 : FD_LOG_WARNING(( "NULL mem" ));
17 0 : return NULL;
18 0 : }
19 :
20 407862 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, FD_ACC_MGR_ALIGN ) ) ) {
21 0 : FD_LOG_WARNING(( "misaligned mem" ));
22 0 : return NULL;
23 0 : }
24 :
25 407862 : fd_memset( mem, 0, FD_ACC_MGR_FOOTPRINT );
26 :
27 407862 : fd_acc_mgr_t * acc_mgr = fd_type_pun( mem );
28 407862 : acc_mgr->funk = funk;
29 407862 : return acc_mgr;
30 :
31 407862 : }
32 :
33 : void *
34 407862 : fd_acc_mgr_delete( fd_acc_mgr_t * acc_mgr ) {
35 :
36 407862 : if( FD_UNLIKELY( !acc_mgr ) ) return NULL;
37 :
38 407862 : memset( acc_mgr, 0, FD_ACC_MGR_FOOTPRINT );
39 407862 : return acc_mgr;
40 407862 : }
41 :
42 : static ulong
43 : fd_rent_lists_key_to_bucket( fd_acc_mgr_t * acc_mgr,
44 0 : fd_funk_rec_t const * rec ) {
45 0 : fd_pubkey_t const * key = fd_type_pun_const( &rec->pair.key[0].uc );
46 0 : ulong prefixX_be = key->ul[0];
47 0 : ulong prefixX = fd_ulong_bswap( prefixX_be );
48 0 : return fd_rent_key_to_partition( prefixX, acc_mgr->part_width, acc_mgr->slots_per_epoch );
49 0 : }
50 :
51 : static uint
52 : fd_rent_lists_cb( fd_funk_rec_t * rec,
53 : uint part_cnt,
54 0 : void * cb_arg ) {
55 0 : (void)part_cnt;
56 :
57 0 : fd_exec_slot_ctx_t * slot_ctx = (fd_exec_slot_ctx_t *)cb_arg;
58 0 : fd_acc_mgr_t * acc_mgr = slot_ctx->acc_mgr;
59 :
60 0 : if( fd_funk_key_is_acc( rec->pair.key ) ) {
61 0 : if( acc_mgr->skip_rent_rewrites ) {
62 0 : void const * data = fd_funk_val( rec, fd_funk_wksp(acc_mgr->funk) );
63 0 : fd_account_meta_t const * metadata = fd_type_pun_const( data );
64 :
65 0 : fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx );
66 0 : ulong required_balance = fd_rent_exempt_minimum_balance( &epoch_bank->rent, metadata->dlen );
67 0 : if( required_balance <= metadata->info.lamports )
68 0 : return FD_FUNK_PART_NULL;
69 0 : }
70 :
71 0 : return (uint)fd_rent_lists_key_to_bucket( acc_mgr, rec );
72 0 : }
73 :
74 0 : return FD_FUNK_PART_NULL;
75 0 : }
76 :
77 : void
78 : fd_acc_mgr_set_slots_per_epoch( fd_exec_slot_ctx_t * slot_ctx,
79 0 : ulong slots_per_epoch ) {
80 0 : fd_acc_mgr_t * acc_mgr = slot_ctx->acc_mgr;
81 :
82 : /* Handle feature activation of 'skip_rent_rewrites' or change of
83 : slots_per_epoch. */
84 :
85 0 : int skip_rent_rewrites = FD_FEATURE_ACTIVE( slot_ctx, skip_rent_rewrites );
86 :
87 0 : if( ( slots_per_epoch == acc_mgr->slots_per_epoch ) &
88 0 : ( skip_rent_rewrites == acc_mgr->skip_rent_rewrites ) )
89 0 : return;
90 :
91 0 : acc_mgr->slots_per_epoch = slots_per_epoch;
92 0 : acc_mgr->skip_rent_rewrites = !!skip_rent_rewrites;
93 0 : acc_mgr->part_width = fd_rent_partition_width( slots_per_epoch );
94 :
95 0 : fd_funk_repartition( acc_mgr->funk, (uint)slots_per_epoch, fd_rent_lists_cb, slot_ctx );
96 0 : }
97 :
98 : fd_account_meta_t const *
99 : fd_acc_mgr_view_raw( fd_acc_mgr_t * acc_mgr,
100 : fd_funk_txn_t const * txn,
101 : fd_pubkey_t const * pubkey,
102 : fd_funk_rec_t const ** orec,
103 : int * opt_err,
104 5399877 : fd_funk_txn_t const ** txn_out ) {
105 :
106 5399877 : fd_funk_rec_key_t id = fd_acc_funk_key( pubkey );
107 5399877 : fd_funk_t * funk = acc_mgr->funk;
108 :
109 5399877 : fd_funk_rec_t const * rec = fd_funk_rec_query_global( funk, txn, &id, txn_out );
110 :
111 5399877 : if( FD_UNLIKELY( !rec || !!( rec->flags & FD_FUNK_REC_FLAG_ERASE ) ) ) {
112 4322757 : fd_int_store_if( !!opt_err, opt_err, FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT );
113 4322757 : return NULL;
114 4322757 : }
115 1077120 : if( NULL != orec )
116 1077105 : *orec = rec;
117 :
118 1077120 : void const * raw = fd_funk_val( rec, fd_funk_wksp(funk) );
119 : // TODO/FIXME: this check causes issues with some metadata writes
120 :
121 1077120 : fd_account_meta_t const * metadata = fd_type_pun_const( raw );
122 1077120 : if( FD_UNLIKELY( metadata->magic != FD_ACCOUNT_META_MAGIC ) ) {
123 0 : fd_int_store_if( !!opt_err, opt_err, FD_ACC_MGR_ERR_WRONG_MAGIC );
124 0 : return NULL;
125 0 : }
126 :
127 1077120 : return metadata;
128 1077120 : }
129 :
130 : int
131 : fd_acc_mgr_view( fd_acc_mgr_t * acc_mgr,
132 : fd_funk_txn_t const * txn,
133 : fd_pubkey_t const * pubkey,
134 4792536 : fd_borrowed_account_t * account) {
135 : /* TODO: re-add this check after consulting on why this builtin program check.
136 : Is it the case that the */
137 : // if( fd_pubkey_is_builtin_program( pubkey )
138 : // || memcmp(pubkey->uc, fd_solana_compute_budget_program_id.uc, sizeof(fd_pubkey_t))==0 ) {
139 : // txn = NULL;
140 : // }
141 4792536 : int err = FD_ACC_MGR_SUCCESS;
142 4792536 : fd_account_meta_t const * meta = fd_acc_mgr_view_raw( acc_mgr, txn, pubkey, &account->const_rec, &err, NULL );
143 4792536 : if( FD_UNLIKELY( !fd_acc_exists( meta ) ) ) {
144 3733179 : if( FD_UNLIKELY( err!=FD_ACC_MGR_SUCCESS ) ) {
145 3715446 : return err;
146 3715446 : }
147 17733 : return FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT;
148 3733179 : }
149 :
150 1059357 : if( FD_UNLIKELY( FD_BORROWED_ACCOUNT_MAGIC != account->magic ) ) {
151 0 : FD_LOG_ERR(( "bad magic for borrowed account - acc: %s, expected: %016lx, got: %016lx", FD_BASE58_ENC_32_ALLOCA( pubkey->uc ), FD_BORROWED_ACCOUNT_MAGIC, account->magic ));
152 0 : }
153 :
154 1059357 : fd_memcpy(account->pubkey, pubkey, sizeof(fd_pubkey_t));
155 :
156 1059357 : account->orig_rec = account->const_rec;
157 1059357 : account->orig_meta = account->const_meta = meta;
158 1059357 : account->orig_data = account->const_data = (uchar const *)meta + meta->hlen;
159 :
160 1059357 : if( ULONG_MAX == account->starting_dlen )
161 1059357 : account->starting_dlen = meta->dlen;
162 :
163 1059357 : if( ULONG_MAX == account->starting_lamports )
164 1059357 : account->starting_lamports = meta->info.lamports;
165 :
166 1059357 : return FD_ACC_MGR_SUCCESS;
167 1059357 : }
168 :
169 : fd_account_meta_t *
170 : fd_acc_mgr_modify_raw( fd_acc_mgr_t * acc_mgr,
171 : fd_funk_txn_t * txn,
172 : fd_pubkey_t const * pubkey,
173 : int do_create,
174 : ulong min_data_sz,
175 : fd_funk_rec_t const * opt_con_rec,
176 : fd_funk_rec_t ** opt_out_rec,
177 1687767 : int * opt_err ) {
178 :
179 1687767 : fd_funk_t * funk = acc_mgr->funk;
180 :
181 1687767 : fd_funk_rec_key_t id = fd_acc_funk_key( pubkey );
182 :
183 : //#ifdef VLOG
184 : // ulong rec_cnt = 0;
185 : // for( fd_funk_rec_t const * rec = fd_funk_txn_first_rec( funk, txn );
186 : // NULL != rec;
187 : // rec = fd_funk_txn_next_rec( funk, rec ) ) {
188 : //
189 : // if( !fd_funk_key_is_acc( rec->pair.key ) ) continue;
190 : //
191 : // FD_LOG_DEBUG(( "fd_acc_mgr_modify_raw: %s create: %s rec_cnt: %d", FD_BASE58_ENC_32_ALLOCA( rec->pair.key->uc ), do_create ? "true" : "false", rec_cnt));
192 : //
193 : // rec_cnt++;
194 : // }
195 : //
196 : // FD_LOG_DEBUG(( "fd_acc_mgr_modify_raw: %s create: %s", FD_BASE58_ENC_32_ALLOCA( pubkey->uc ), do_create ? "true" : "false"));
197 : //#endif
198 :
199 1687767 : int funk_err = FD_FUNK_SUCCESS;
200 1687767 : fd_funk_rec_t * rec = fd_funk_rec_write_prepare( funk, txn, &id, sizeof(fd_account_meta_t)+min_data_sz, do_create, opt_con_rec, &funk_err );
201 :
202 1687767 : if( FD_UNLIKELY( !rec ) ) {
203 0 : if( FD_LIKELY( funk_err==FD_FUNK_ERR_KEY ) ) {
204 0 : fd_int_store_if( !!opt_err, opt_err, FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT );
205 0 : return NULL;
206 0 : }
207 : /* Irrecoverable funky internal error [[noreturn]] */
208 0 : FD_LOG_ERR(( "fd_funk_rec_write_prepare(%s) failed (%i-%s)", FD_BASE58_ENC_32_ALLOCA( pubkey->key ), funk_err, fd_funk_strerror( funk_err ) ));
209 0 : }
210 :
211 1687767 : if (NULL != opt_out_rec)
212 1687767 : *opt_out_rec = rec;
213 :
214 : // At this point, we don't know if the record WILL be rent exempt so
215 : // it is safer to just stick it into the partition and look at it later.
216 1687767 : if ( acc_mgr->slots_per_epoch != 0 )
217 0 : fd_funk_part_set(funk, rec, (uint)fd_rent_lists_key_to_bucket( acc_mgr, rec ));
218 :
219 1687767 : fd_account_meta_t * ret = fd_funk_val( rec, fd_funk_wksp( funk ) );
220 :
221 1687767 : if( do_create && ret->magic==0UL ) {
222 803628 : fd_account_meta_init( ret );
223 803628 : }
224 :
225 1687767 : if( ret->magic != FD_ACCOUNT_META_MAGIC ) {
226 0 : fd_int_store_if( !!opt_err, opt_err, FD_ACC_MGR_ERR_WRONG_MAGIC );
227 0 : return NULL;
228 0 : }
229 :
230 1687767 : return ret;
231 1687767 : }
232 :
233 : int
234 : fd_acc_mgr_modify( fd_acc_mgr_t * acc_mgr,
235 : fd_funk_txn_t * txn,
236 : fd_pubkey_t const * pubkey,
237 : int do_create,
238 : ulong min_data_sz,
239 1687761 : fd_borrowed_account_t * account ) {
240 1687761 : int err = FD_ACC_MGR_SUCCESS;
241 :
242 1687761 : fd_account_meta_t * meta = fd_acc_mgr_modify_raw( acc_mgr, txn, pubkey, do_create, min_data_sz, account->const_rec, &account->rec, &err );
243 1687761 : if( FD_UNLIKELY( !meta ) ) return err;
244 :
245 1687761 : assert( account->magic == FD_BORROWED_ACCOUNT_MAGIC );
246 :
247 0 : fd_memcpy(account->pubkey, pubkey, sizeof(fd_pubkey_t));
248 :
249 1687761 : if( FD_UNLIKELY( meta->magic != FD_ACCOUNT_META_MAGIC ) )
250 0 : return FD_ACC_MGR_ERR_WRONG_MAGIC;
251 :
252 : #ifdef VLOG
253 : FD_LOG_DEBUG(( "fd_acc_mgr_modify: %s create: %s lamports: %ld owner: %s executable: %s, rent_epoch: %ld, data_len: %ld",
254 : FD_BASE58_ENC_32_ALLOCA( pubkey->uc ),
255 : do_create ? "true" : "false",
256 : meta->info.lamports,
257 : FD_BASE58_ENC_32_ALLOCA( meta->info.owner ),
258 : meta->info.executable ? "true" : "false",
259 : meta->info.rent_epoch, meta->dlen ));
260 : #endif
261 :
262 1687761 : account->orig_rec = account->const_rec = account->rec;
263 1687761 : account->orig_meta = account->const_meta = account->meta = meta;
264 1687761 : account->orig_data = account->const_data = account->data = (uchar *)meta + meta->hlen;
265 :
266 1687761 : if( ULONG_MAX == account->starting_dlen )
267 1687761 : account->starting_dlen = meta->dlen;
268 :
269 1687761 : if( ULONG_MAX == account->starting_lamports )
270 1687761 : account->starting_lamports = meta->info.lamports;
271 :
272 1687761 : return FD_ACC_MGR_SUCCESS;
273 1687761 : }
274 :
275 : FD_FN_CONST char const *
276 0 : fd_acc_mgr_strerror( int err ) {
277 0 : switch( err ) {
278 0 : case FD_ACC_MGR_SUCCESS:
279 0 : return "success";
280 0 : case FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT:
281 0 : return "unknown account";
282 0 : case FD_ACC_MGR_ERR_WRITE_FAILED:
283 0 : return "write failed";
284 0 : case FD_ACC_MGR_ERR_READ_FAILED:
285 0 : return "read failed";
286 0 : case FD_ACC_MGR_ERR_WRONG_MAGIC:
287 0 : return "wrong magic";
288 0 : default:
289 0 : return "unknown";
290 0 : }
291 0 : }
292 :
293 : int
294 : fd_acc_mgr_save( fd_acc_mgr_t * acc_mgr,
295 0 : fd_borrowed_account_t * account ) {
296 0 : if( account->meta == NULL || account->rec == NULL ) {
297 : // The meta is NULL so the account is not writable.
298 0 : FD_LOG_DEBUG(( "fd_acc_mgr_save: account is not writable: %s", FD_BASE58_ENC_32_ALLOCA( account->pubkey ) ));
299 0 : return FD_ACC_MGR_SUCCESS;
300 0 : }
301 :
302 0 : fd_wksp_t * wksp = fd_funk_wksp( acc_mgr->funk );
303 0 : ulong reclen = sizeof(fd_account_meta_t)+account->const_meta->dlen;
304 0 : uchar * raw = fd_funk_val( account->rec, wksp );
305 0 : fd_memcpy( raw, account->meta, reclen );
306 :
307 0 : return FD_ACC_MGR_SUCCESS;
308 0 : }
309 :
310 : int
311 : fd_acc_mgr_save_non_tpool( fd_acc_mgr_t * acc_mgr,
312 : fd_funk_txn_t * txn,
313 0 : fd_borrowed_account_t * account ) {
314 0 : fd_funk_rec_key_t key = fd_acc_funk_key( account->pubkey );
315 0 : fd_funk_t * funk = acc_mgr->funk;
316 0 : fd_funk_rec_t * rec = (fd_funk_rec_t *)fd_funk_rec_query( funk, txn, &key );
317 0 : if( rec == NULL ) {
318 0 : int err;
319 0 : fd_funk_start_write( acc_mgr->funk );
320 0 : rec = (fd_funk_rec_t *)fd_funk_rec_insert( funk, txn, &key, &err );
321 0 : fd_funk_end_write( acc_mgr->funk );
322 0 : if( rec == NULL ) FD_LOG_ERR(( "unable to insert a new record, error %d", err ));
323 0 : }
324 0 : account->rec = rec;
325 0 : if ( acc_mgr->slots_per_epoch != 0 )
326 0 : fd_funk_part_set(funk, rec, (uint)fd_rent_lists_key_to_bucket( acc_mgr, rec ));
327 0 : ulong reclen = sizeof(fd_account_meta_t)+account->const_meta->dlen;
328 0 : fd_wksp_t * wksp = fd_funk_wksp( acc_mgr->funk );
329 0 : int err;
330 0 : if( fd_funk_val_truncate( account->rec, reclen, fd_funk_alloc( acc_mgr->funk, wksp ), wksp, &err ) == NULL ) {
331 0 : FD_LOG_ERR(( "unable to allocate account value, err %d", err ));
332 0 : }
333 0 : return fd_acc_mgr_save( acc_mgr, account );
334 0 : }
335 :
336 : void
337 0 : fd_acc_mgr_lock( fd_acc_mgr_t * acc_mgr ) {
338 0 : FD_TEST( !acc_mgr->is_locked );
339 0 : acc_mgr->is_locked = 1;
340 0 : }
341 :
342 : void
343 0 : fd_acc_mgr_unlock( fd_acc_mgr_t * acc_mgr ) {
344 0 : FD_TEST( acc_mgr->is_locked );
345 0 : acc_mgr->is_locked = 0;
346 0 : }
347 :
348 : struct fd_acc_mgr_save_task_args {
349 : fd_acc_mgr_t * acc_mgr;
350 : };
351 : typedef struct fd_acc_mgr_save_task_args fd_acc_mgr_save_task_args_t;
352 :
353 : struct fd_acc_mgr_save_task_info {
354 : fd_borrowed_account_t * * accounts;
355 : ulong accounts_cnt;
356 : int result;
357 : };
358 : typedef struct fd_acc_mgr_save_task_info fd_acc_mgr_save_task_info_t;
359 :
360 : static void
361 : fd_acc_mgr_save_task( void *tpool,
362 : ulong t0 FD_PARAM_UNUSED, ulong t1 FD_PARAM_UNUSED,
363 : void *args FD_PARAM_UNUSED,
364 : void *reduce FD_PARAM_UNUSED, ulong stride FD_PARAM_UNUSED,
365 : ulong l0 FD_PARAM_UNUSED, ulong l1 FD_PARAM_UNUSED,
366 : ulong m0, ulong m1 FD_PARAM_UNUSED,
367 0 : ulong n0 FD_PARAM_UNUSED, ulong n1 FD_PARAM_UNUSED ) {
368 0 : fd_acc_mgr_save_task_args_t * task_args = (fd_acc_mgr_save_task_args_t *)args;
369 0 : fd_acc_mgr_save_task_info_t * task_info = (fd_acc_mgr_save_task_info_t *)tpool + m0;
370 :
371 0 : for( ulong i = 0; i < task_info->accounts_cnt; i++ ) {
372 0 : int err = fd_acc_mgr_save(task_args->acc_mgr,task_info->accounts[i] );
373 0 : if( FD_UNLIKELY( err != FD_ACC_MGR_SUCCESS ) ) {
374 0 : task_info->result = err;
375 0 : return;
376 0 : }
377 0 : }
378 0 : task_info->result = FD_ACC_MGR_SUCCESS;
379 0 : }
380 :
381 : int
382 : fd_acc_mgr_save_many_tpool( fd_acc_mgr_t * acc_mgr,
383 : fd_funk_txn_t * txn,
384 : fd_borrowed_account_t * * accounts,
385 : ulong accounts_cnt,
386 0 : fd_tpool_t * tpool ) {
387 0 : FD_SCRATCH_SCOPE_BEGIN {
388 0 : fd_funk_t * funk = acc_mgr->funk;
389 0 : fd_wksp_t * wksp = fd_funk_wksp( funk );
390 0 : fd_funk_rec_t * rec_map = fd_funk_rec_map( funk, wksp );
391 :
392 0 : ulong batch_cnt = fd_ulong_min(
393 0 : fd_funk_rec_map_private_list_cnt( fd_funk_rec_map_key_max( rec_map ) ),
394 0 : fd_ulong_pow2_up( fd_tpool_worker_cnt( tpool ) )
395 0 : );
396 0 : ulong batch_mask = (batch_cnt - 1UL);
397 :
398 0 : ulong * batch_szs = fd_scratch_alloc( 8UL, batch_cnt * sizeof(ulong) );
399 0 : fd_memset( batch_szs, 0, batch_cnt * sizeof(ulong) );
400 :
401 : /* Compute the batch sizes */
402 0 : for( ulong i = 0; i < accounts_cnt; i++ ) {
403 0 : ulong batch_idx = i & batch_mask;
404 0 : batch_szs[batch_idx]++;
405 0 : }
406 :
407 0 : fd_borrowed_account_t * * task_accounts = fd_scratch_alloc( 8UL, accounts_cnt * sizeof(fd_borrowed_account_t *) );
408 0 : fd_acc_mgr_save_task_info_t * task_infos = fd_scratch_alloc( 8UL, batch_cnt * sizeof(fd_acc_mgr_save_task_info_t) );
409 0 : fd_borrowed_account_t * * task_accounts_cursor = task_accounts;
410 :
411 : /* Construct the batches */
412 0 : for( ulong i = 0; i < batch_cnt; i++ ) {
413 0 : ulong batch_sz = batch_szs[i];
414 0 : fd_acc_mgr_save_task_info_t * task_info = &task_infos[i];
415 :
416 0 : task_info->accounts_cnt = 0;
417 0 : task_info->accounts = task_accounts_cursor;
418 0 : task_info->result = 0;
419 :
420 0 : task_accounts_cursor += batch_sz;
421 0 : }
422 :
423 0 : fd_funk_start_write( funk );
424 :
425 0 : for( ulong i = 0; i < accounts_cnt; i++ ) {
426 0 : fd_borrowed_account_t * account = accounts[i];
427 :
428 0 : ulong batch_idx = i & batch_mask;
429 0 : fd_acc_mgr_save_task_info_t * task_info = &task_infos[batch_idx];
430 0 : task_info->accounts[task_info->accounts_cnt++] = account;
431 0 : fd_funk_rec_key_t key = fd_acc_funk_key( account->pubkey );
432 0 : fd_funk_rec_t * rec = (fd_funk_rec_t *)fd_funk_rec_query( funk, txn, &key );
433 0 : if( rec == NULL ) {
434 0 : int err;
435 0 : rec = (fd_funk_rec_t *)fd_funk_rec_insert( funk, txn, &key, &err );
436 0 : if( rec == NULL ) FD_LOG_ERR(( "unable to insert a new record, error %d", err ));
437 0 : }
438 0 : account->rec = rec;
439 0 : if ( acc_mgr->slots_per_epoch != 0 )
440 0 : fd_funk_part_set(funk, rec, (uint)fd_rent_lists_key_to_bucket( acc_mgr, rec ));
441 :
442 : /* This check is to prevent a seg fault in the case where an account with
443 : null data tries to get saved. This notably happens if firedancer is
444 : attemping to execute a bad block. This should NEVER happen in the case
445 : of a proper replay. */
446 0 : if( FD_UNLIKELY( !account->const_meta ) ) {
447 0 : FD_LOG_ERR(( "An account likely does not exist. This block could be invalid." ));
448 0 : }
449 :
450 0 : ulong reclen = sizeof(fd_account_meta_t)+account->const_meta->dlen;
451 0 : int err;
452 0 : if( fd_funk_val_truncate( account->rec, reclen, fd_funk_alloc( acc_mgr->funk, wksp ), wksp, &err ) == NULL ) {
453 0 : FD_LOG_ERR(( "unable to allocate account value, err %d", err ));
454 0 : }
455 0 : }
456 :
457 0 : fd_acc_mgr_save_task_args_t task_args = {
458 0 : .acc_mgr = acc_mgr
459 0 : };
460 :
461 : /* Save accounts in a thread pool */
462 :
463 0 : fd_tpool_exec_all_rrobin( tpool, 0, fd_tpool_worker_cnt( tpool ), fd_acc_mgr_save_task, task_infos, &task_args, NULL, 1, 0, batch_cnt );
464 :
465 0 : fd_funk_end_write( funk );
466 :
467 : /* Check results */
468 0 : for( ulong i = 0; i < batch_cnt; i++ ) {
469 0 : fd_acc_mgr_save_task_info_t * task_info = &task_infos[i];
470 0 : if( task_info->result != FD_ACC_MGR_SUCCESS ) {
471 0 : return task_info->result;
472 0 : }
473 0 : }
474 :
475 0 : return FD_ACC_MGR_SUCCESS;
476 0 : } FD_SCRATCH_SCOPE_END;
477 0 : }
|