Skip to content

Commit fc6e350

Browse files
asiegel-jtripatel-fd
authored andcommitted
fixed test_funk_concur2
1 parent 59fc3fb commit fc6e350

File tree

5 files changed

+90
-240
lines changed

5 files changed

+90
-240
lines changed

src/flamenco/runtime/program/fd_program_cache.c

Lines changed: 14 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -583,49 +583,26 @@ FD_SPAD_FRAME_BEGIN( runtime_spad ) {
583583
record_sz = fd_program_cache_entry_footprint( &elf_info );
584584
}
585585

586-
/* Insert a new funk record, replacing the existing one if needed.
587-
min_sz==0 since the actual allocation happens below. */
588-
fd_funk_rec_insert_para( slot_ctx->funk, slot_ctx->xid, &id );
589-
590-
/* Modify the record within the current funk txn */
591-
fd_funk_rec_query_t query[1];
592-
fd_funk_rec_t * rec = fd_funk_rec_modify( slot_ctx->funk, slot_ctx->xid, &id, query );
593-
if( FD_UNLIKELY( !rec ) ) {
594-
/* The record does not exist (somehow). Ideally this should never
595-
happen as this function is called in a single-threaded context. */
596-
FD_LOG_CRIT(( "Failed to modify the BPF program cache record. Perhaps there is a race condition?" ));
597-
}
598-
599586
/* Resize the record to the new footprint if needed */
600-
void * data = fd_funk_val_truncate(
601-
rec,
602-
fd_funk_alloc( slot_ctx->funk ),
603-
fd_funk_wksp( slot_ctx->funk ),
604-
0UL,
605-
record_sz,
606-
NULL );
607-
587+
uchar data[ record_sz ];
608588
fd_program_cache_entry_t * writable_entry = fd_type_pun( data );
609589

610590
/* If the ELF header parsing failed, publish a failed verification
611591
record. */
612592
if( FD_UNLIKELY( failed_elf_parsing ) ) {
613593
fd_program_cache_entry_set_failed_verification( writable_entry, current_slot );
614-
fd_funk_rec_modify_publish( query );
615-
return;
616-
}
617-
618-
/* Validate the sBPF program. This will set the program's flags
619-
accordingly. We publish the funk record regardless of the return
620-
code. */
621-
writable_entry = fd_program_cache_entry_new( data, &elf_info, last_slot_modified, current_slot );
622-
int res = fd_program_cache_validate_sbpf_program( slot_ctx, &elf_info, program_data, program_data_len, runtime_spad, writable_entry );
623-
if( FD_UNLIKELY( res ) ) {
624-
FD_LOG_DEBUG(( "fd_program_cache_validate_sbpf_program() failed" ));
594+
} else {
595+
/* Validate the sBPF program. This will set the program's flags
596+
accordingly. We publish the funk record regardless of the return
597+
code. */
598+
writable_entry = fd_program_cache_entry_new( data, &elf_info, last_slot_modified, current_slot );
599+
int res = fd_program_cache_validate_sbpf_program( slot_ctx, &elf_info, program_data, program_data_len, runtime_spad, writable_entry );
600+
if( FD_UNLIKELY( res ) ) {
601+
FD_LOG_DEBUG(( "fd_program_cache_validate_sbpf_program() failed" ));
602+
}
625603
}
626604

627-
/* Finish modifying and release lock */
628-
fd_funk_rec_modify_publish( query );
605+
fd_funk_rec_insert_para( slot_ctx->funk, slot_ctx->xid, &id, alignof(fd_program_cache_entry_t), record_sz, writable_entry );
629606

630607
} FD_SPAD_FRAME_END;
631608
}
@@ -653,35 +630,7 @@ fd_program_cache_queue_program_for_reverification( fd_funk_t * fun
653630

654631
/* Ensure the record is in the current funk transaction */
655632
fd_funk_rec_key_t id = fd_program_cache_key( program_key );
656-
fd_funk_rec_insert_para( funk, xid, &id );
657-
658-
/* Modify the record within the current funk txn */
659-
fd_funk_rec_query_t query[1];
660-
fd_funk_rec_t * rec = fd_funk_rec_modify( funk, xid, &id, query );
661-
if( FD_UNLIKELY( !rec ) ) {
662-
/* The record does not exist (somehow). Ideally this should never
663-
happen since this function is called in a single-threaded
664-
context. */
665-
FD_LOG_CRIT(( "Failed to modify the BPF program cache record. Perhaps there is a race condition?" ));
666-
}
667-
668-
/* Insert a tombstone */
669-
if( FD_UNLIKELY( !fd_funk_val_truncate(
670-
rec,
671-
fd_funk_alloc( funk ),
672-
fd_funk_wksp( funk ),
673-
alignof(fd_program_cache_entry_t),
674-
sizeof(fd_program_cache_entry_t),
675-
NULL ) ) ) {
676-
FD_LOG_ERR(( "fd_funk_val_truncate() failed (out of memory?)" ));
677-
}
678-
679-
fd_program_cache_entry_t * entry = fd_funk_val( rec, fd_funk_wksp( funk ) );
680-
*entry = (fd_program_cache_entry_t) {
681-
.magic = FD_PROGRAM_CACHE_ENTRY_MAGIC,
682-
.last_slot_modified = current_slot
683-
};
684-
685-
/* Finish modifying and release lock */
686-
fd_funk_rec_modify_publish( query );
633+
fd_program_cache_entry_t entry = *existing_entry;
634+
entry.last_slot_modified = current_slot;
635+
fd_funk_rec_insert_para( funk, xid, &id, alignof(fd_program_cache_entry_t), sizeof(fd_program_cache_entry_t), &entry );
687636
}

src/flamenco/runtime/program/test_program_cache.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ test_program_in_cache_queued_for_reverification( void ) {
305305
FD_TEST( valid_prog->magic==FD_PROGRAM_CACHE_ENTRY_MAGIC );
306306
FD_TEST( !valid_prog->failed_verification );
307307
FD_TEST( valid_prog->last_slot_modified==future_slot );
308-
FD_TEST( valid_prog->last_slot_verified==0UL );
308+
FD_TEST( valid_prog->last_slot_verified==original_slot );
309309
FD_TEST( valid_prog->last_slot_modified>original_slot );
310310

311311
/* Reverify the cache entry at the future slot */
@@ -409,7 +409,7 @@ test_program_in_cache_queued_for_reverification_and_processed( void ) {
409409
FD_TEST( valid_prog->magic==FD_PROGRAM_CACHE_ENTRY_MAGIC );
410410
FD_TEST( !valid_prog->failed_verification );
411411
FD_TEST( valid_prog->last_slot_modified==future_slot );
412-
FD_TEST( valid_prog->last_slot_verified==0UL );
412+
FD_TEST( valid_prog->last_slot_verified==original_slot );
413413
FD_TEST( valid_prog->last_slot_modified>original_slot );
414414

415415
/* Fast forward to a future slot */

src/funk/fd_funk_rec.c

Lines changed: 36 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -396,130 +396,52 @@ fd_funk_rec_cancel( fd_funk_t * funk,
396396
fd_funk_rec_pool_release( funk->rec_pool, prepare->rec, 1 );
397397
}
398398

399-
static void
400-
fd_funk_rec_txn_publish( fd_funk_t * funk,
401-
fd_funk_rec_prepare_t * prepare ) {
402-
fd_funk_rec_t * rec = prepare->rec;
403-
uint * rec_head_idx = prepare->rec_head_idx;
404-
uint * rec_tail_idx = prepare->rec_tail_idx;
405-
406-
uint rec_prev_idx;
407-
uint rec_idx = (uint)( rec - funk->rec_pool->ele );
408-
rec_prev_idx = *rec_tail_idx;
409-
*rec_tail_idx = rec_idx;
410-
rec->prev_idx = rec_prev_idx;
411-
rec->next_idx = FD_FUNK_REC_IDX_NULL;
412-
if( fd_funk_rec_idx_is_null( rec_prev_idx ) ) {
413-
*rec_head_idx = rec_idx;
414-
} else {
415-
funk->rec_pool->ele[ rec_prev_idx ].next_idx = rec_idx;
416-
}
417-
418-
if( FD_UNLIKELY( fd_funk_rec_map_txn_insert( funk->rec_map, rec ) ) ) {
419-
FD_LOG_CRIT(( "fd_funk_rec_map_insert failed" ));
420-
}
421-
}
422-
423-
void
399+
int
424400
fd_funk_rec_insert_para( fd_funk_t * funk,
425401
fd_funk_txn_xid_t const * xid,
426-
fd_funk_rec_key_t const * key ) {
402+
fd_funk_rec_key_t const * key,
403+
ulong val_align,
404+
ulong val_sz,
405+
void * val ) {
406+
if( FD_UNLIKELY( !funk ) ) FD_LOG_ERR(( "NULL funk" ));
407+
if( FD_UNLIKELY( !xid ) ) FD_LOG_ERR(( "NULL xid" ));
408+
if( FD_UNLIKELY( !key ) ) FD_LOG_ERR(( "NULL key" ));
409+
if( FD_UNLIKELY( !val && val_sz ) ) FD_LOG_ERR(( "NULL val" ));
427410

428-
/* TODO: There is probably a cleaner way to allocate the txn memory. */
429-
430-
/* See the header comment for why the max is 2. */
431-
#define MAX_TXN_KEY_CNT (2UL)
432-
uchar txn_mem[ fd_funk_rec_map_txn_footprint( MAX_TXN_KEY_CNT ) ] __attribute__((aligned(alignof(fd_funk_rec_map_txn_t))));
433-
434-
/* First, we will do a global query to find a version of the record
435-
from either the current transaction or one of its ancestors. */
436-
437-
fd_funk_rec_t const * rec_glob = NULL;
438-
fd_funk_txn_xid_t txn_glob[1] = {0};
411+
fd_funk_xid_key_pair_t pair[1];
412+
fd_funk_rec_key_set_pair( pair, xid, key );
439413

440414
for(;;) {
441-
fd_funk_rec_query_t query_glob[1];
442-
fd_funk_txn_t const * found_txn = NULL;
443-
rec_glob = fd_funk_rec_query_try_global( funk, xid, key, &found_txn, query_glob );
444-
if( found_txn ) fd_funk_txn_xid_copy( txn_glob, &found_txn->xid );
445-
else fd_funk_txn_xid_copy( txn_glob, fd_funk_last_publish( funk ) );
446-
447-
/* If the record exists and already exists in the specified funk
448-
txn, we can return successfully.
449-
450-
TODO: This should probably also check that the record has a large
451-
enough size, i.e. rec_glob >= min_sz. */
452-
if( rec_glob && fd_funk_txn_xid_eq( txn_glob, xid ) ) {
453-
return;
415+
/* See if the record already exists. */
416+
fd_funk_rec_query_t query[1];
417+
int err = fd_funk_rec_map_query_try( funk->rec_map, pair, NULL, query, 0 );
418+
if( err == FD_MAP_SUCCESS ) {
419+
fd_funk_rec_t * rec = fd_funk_rec_map_query_ele( query );
420+
/* Set the value of the record */
421+
if( !fd_funk_val_truncate( rec, fd_funk_alloc( funk ), fd_funk_wksp( funk ), val_align, val_sz, &err ) ) {
422+
FD_LOG_ERR(( "fd_funk_val_truncate() failed (out of memory?)" ));
423+
return err;
424+
}
425+
memcpy( fd_funk_val( rec, fd_funk_wksp( funk ) ), val, val_sz );
426+
return FD_FUNK_SUCCESS;
454427
}
455428

456-
if( rec_glob && fd_funk_rec_query_test( query_glob )==FD_FUNK_SUCCESS ) {
457-
break;
429+
/* The record doesn't exist. Create it. */
430+
fd_funk_rec_prepare_t prepare[1];
431+
fd_funk_rec_t * rec = fd_funk_rec_prepare( funk, xid, key, prepare, &err );
432+
if( FD_UNLIKELY( !rec ) ) {
433+
FD_LOG_CRIT(( "fd_funk_rec_prepare returned err=%d", err ));
434+
return err;
458435
}
459-
}
460-
461-
/* At this point, we need to atomically clone the record and copy
462-
in the contents of the global record. We at most will be trying to
463-
create a txn with two record keys. If the key exists in some
464-
ancestor txn, than we need to add the ancestor key to the txn. We
465-
will always need to add the current key to the txn. */
466-
/* TODO: Turn key_max into a const. */
467-
468-
fd_funk_rec_map_txn_t * map_txn = fd_funk_rec_map_txn_init( txn_mem, funk->rec_map, MAX_TXN_KEY_CNT );
469-
470-
fd_funk_xid_key_pair_t pair[1];
471-
fd_funk_rec_key_set_pair( pair, xid, key );
472-
473-
fd_funk_rec_map_txn_add( map_txn, pair, 1 );
474-
475-
fd_funk_xid_key_pair_t pair_glob[1];
476-
if( rec_glob ) {
477-
fd_funk_rec_key_set_pair( pair_glob, txn_glob, key );
478-
fd_funk_rec_map_txn_add( map_txn, pair_glob, 1 );
479-
}
480-
481-
/* Now that the keys are in the txn, we can try to start the
482-
transaction on the record_map. */
483-
484-
int err = fd_funk_rec_map_txn_try( map_txn, FD_MAP_FLAG_BLOCKING );
485-
if( FD_UNLIKELY( err != FD_MAP_SUCCESS ) ) {
486-
FD_LOG_CRIT(( "fd_funk_rec_map_txn_try returned err %d", err ));
487-
}
488-
489-
/* We are now in a txn try with a lock on both record keys. */
490-
491-
/* First we need to make sure that the record hasn't been created yet. */
492-
fd_funk_rec_map_query_t query[1];
493-
err = fd_funk_rec_map_txn_query( funk->rec_map, pair, NULL, query, FD_MAP_FLAG_BLOCKING );
494-
if( FD_UNLIKELY( err==FD_MAP_SUCCESS ) ) {
495-
/* The key has been inserted. We need to gracefully exit the txn. */
496-
err = fd_funk_rec_map_txn_test( map_txn );
497-
if( FD_UNLIKELY( err != FD_MAP_SUCCESS ) ) {
498-
FD_LOG_CRIT(( "fd_funk_rec_map_txn_test returned err %d", err ));
436+
/* Set the value of the record */
437+
if( !fd_funk_val_truncate( rec, fd_funk_alloc( funk ), fd_funk_wksp( funk ), val_align, val_sz, &err ) ) {
438+
FD_LOG_ERR(( "fd_funk_val_truncate() failed (out of memory?)" ));
439+
return err;
499440
}
500-
fd_funk_rec_map_txn_fini( map_txn );
501-
return;
502-
}
503-
504-
/* If we are at this point, we know for certain that the record hasn't
505-
been created yet. We will copy in the record from the global txn
506-
(if one exists). */
507-
508-
fd_funk_rec_prepare_t prepare[1];
509-
fd_funk_rec_prepare( funk, xid, key, prepare, &err );
510-
if( FD_UNLIKELY( err ) ) {
511-
FD_LOG_CRIT(( "fd_funk_rec_prepare returned err=%d", err ));
512-
}
513-
fd_funk_rec_txn_publish( funk, prepare );
514-
515-
err = fd_funk_rec_map_txn_test( map_txn );
516-
if( FD_UNLIKELY( err != FD_MAP_SUCCESS ) ) {
517-
FD_LOG_CRIT(( "fd_funk_rec_map_txn_test returned err %d", err ));
441+
memcpy( fd_funk_val( rec, fd_funk_wksp( funk ) ), val, val_sz );
442+
fd_funk_rec_publish( funk, prepare );
443+
return FD_FUNK_SUCCESS;
518444
}
519-
520-
fd_funk_rec_map_txn_fini( map_txn );
521-
522-
#undef MAX_TXN_KEY_CNT
523445
}
524446

525447
fd_funk_rec_t *

src/funk/fd_funk_rec.h

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -332,28 +332,19 @@ fd_funk_rec_clone( fd_funk_t * funk,
332332
Detailed Behavior:
333333
334334
More specifically, first this function will query the transaction
335-
stack to identify what the youngest transaction with the key is. If
336-
a record is found in the current transaction then it will exit.
337-
In the case where a record is found in some ancestor txn or if the
338-
record doesn't exist, the function will then acquire a lock on the
339-
keypair of the youngest ancestor account (if it exists) and the
340-
keypair of the account we want to create. These two keys are
341-
guaranteed to be on the same hash chain so in practice we will just
342-
be locking the hash chain for the key.
343-
344-
Once this lock is acquired, we will query the keypair for the keypair
345-
we are going to create to make sure that it wasn't added in the time
346-
that we were attempting to acquire the lock. If a keypair is found,
347-
we will free the lock and exit the function.
348-
349-
Otherwise, we will allocate a new account record. Now we will add
350-
this into the record map. At this point, we can now free the lock on
351-
the hash chain. */
335+
stack to identify what the youngest transaction with the key is.
336+
If a record is found in some ancestor txn or if the
337+
record doesn't exist, we will allocate a new account record and add
338+
this into the transaction. In either case, the record is set to the
339+
given value. */
352340

353-
void
341+
int
354342
fd_funk_rec_insert_para( fd_funk_t * funk,
355343
fd_funk_txn_xid_t const * xid,
356-
fd_funk_rec_key_t const * key );
344+
fd_funk_rec_key_t const * key,
345+
ulong val_align,
346+
ulong val_sz,
347+
void * val );
357348

358349
/* fd_funk_rec_remove removes the live record with the
359350
given (xid,key) from funk. Returns FD_FUNK_SUCCESS (0) on

0 commit comments

Comments
 (0)