Skip to content

Commit 680e12c

Browse files
riptlripatel-fd
authored andcommitted
progcache: fix dedup logic
Fixes a bug where the progcache user APIs did not cooperatively dedup insertions of the same records.
1 parent 47450df commit 680e12c

File tree

2 files changed

+32
-18
lines changed

2 files changed

+32
-18
lines changed

src/flamenco/progcache/fd_progcache_user.c

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -357,8 +357,10 @@ static int
357357
fd_progcache_push( fd_progcache_t * cache,
358358
fd_funk_txn_t * txn,
359359
fd_funk_rec_t * rec,
360-
void const * prog_addr ) {
360+
void const * prog_addr,
361+
fd_funk_rec_t ** dup_rec ) {
361362
fd_funk_t * funk = cache->funk;
363+
*dup_rec = NULL;
362364

363365
/* Phase 1: Determine record's xid-key pair */
364366

@@ -385,21 +387,32 @@ fd_progcache_push( fd_progcache_t * cache,
385387
FD_LOG_CRIT(( "Failed to insert progcache record: canont lock funk rec map chain: %i-%s", txn_err, fd_map_strerror( txn_err ) ));
386388
}
387389

388-
/* Phase 3: Atomically add record to funk txn's record list */
390+
/* Phase 3: Check if record exists */
389391

390-
int insert_err = fd_funk_rec_map_txn_insert( funk->rec_map, rec );
391-
if( FD_UNLIKELY( insert_err==FD_MAP_ERR_KEY ) ) {
392+
fd_funk_rec_map_query_t query[1];
393+
int query_err = fd_funk_rec_map_txn_query( funk->rec_map, &rec->pair, NULL, query, 0 );
394+
if( FD_UNLIKELY( query_err==FD_MAP_SUCCESS ) ) {
392395
fd_funk_rec_map_txn_test( map_txn );
393396
fd_funk_rec_map_txn_fini( map_txn );
397+
*dup_rec = query->ele;
394398
return 0; /* another thread was faster */
399+
} else if( FD_UNLIKELY( query_err!=FD_MAP_ERR_KEY ) ) {
400+
FD_LOG_CRIT(( "fd_funk_rec_map_txn_query failed: %i-%s", query_err, fd_map_strerror( query_err ) ));
401+
}
402+
403+
/* Phase 4: Insert new record */
404+
405+
int insert_err = fd_funk_rec_map_txn_insert( funk->rec_map, rec );
406+
if( FD_UNLIKELY( insert_err!=FD_MAP_SUCCESS ) ) {
407+
FD_LOG_CRIT(( "fd_funk_rec_map_txn_insert failed: %i-%s", insert_err, fd_map_strerror( insert_err ) ));
395408
}
396409

397410
/* At this point, another thread could aggressively evict this entry.
398411
But this entry is not yet present in rec_map! This is why we hold
399412
a lock on the rec_map chain -- the rec_map_remove executed by the
400413
eviction will be sequenced after completion of phase 5. */
401414

402-
/* Phase 4: Insert rec into rec_map */
415+
/* Phase 5: Insert rec into rec_map */
403416

404417
if( txn ) {
405418
fd_funk_rec_push_tail( funk->rec_pool->ele,
@@ -408,7 +421,7 @@ fd_progcache_push( fd_progcache_t * cache,
408421
&txn->rec_tail_idx );
409422
}
410423

411-
/* Phase 5: Finish rec_map transaction */
424+
/* Phase 6: Finish rec_map transaction */
412425

413426
int test_err = fd_funk_rec_map_txn_test( map_txn );
414427
if( FD_UNLIKELY( test_err!=FD_MAP_SUCCESS ) ) FD_LOG_CRIT(( "fd_funk_rec_map_txn_test failed: %i-%s", test_err, fd_map_strerror( test_err ) ));
@@ -577,7 +590,8 @@ fd_progcache_insert( fd_progcache_t * cache,
577590

578591
/* Publish cache entry to funk index */
579592

580-
int push_ok = fd_progcache_push( cache, txn, funk_rec, prog_addr );
593+
fd_funk_rec_t * dup_rec = NULL;
594+
int push_ok = fd_progcache_push( cache, txn, funk_rec, prog_addr, &dup_rec );
581595

582596
/* Done modifying transaction */
583597

@@ -588,12 +602,11 @@ fd_progcache_insert( fd_progcache_t * cache,
588602
EVICTED AFTER PEEK? */
589603

590604
if( !push_ok ) {
591-
fd_progcache_rec_t const * other = fd_progcache_peek( cache, load_xid, prog_addr, env->epoch_slot0 );
592-
if( FD_UNLIKELY( !other ) ) {
593-
FD_LOG_CRIT(( "fd_progcache_push/fd_progcache_peek data race detected" ));
594-
}
605+
FD_TEST( dup_rec );
606+
fd_funk_val_flush( funk_rec, funk->alloc, funk->wksp );
607+
fd_funk_rec_pool_release( funk->rec_pool, funk_rec, 1 );
595608
cache->metrics->dup_insert_cnt++;
596-
return other;
609+
return fd_funk_val_const( dup_rec, funk->wksp );
597610
}
598611

599612
cache->metrics->fill_cnt++;
@@ -681,7 +694,8 @@ fd_progcache_invalidate( fd_progcache_t * cache,
681694

682695
/* Publish cache entry to funk index */
683696

684-
int push_ok = fd_progcache_push( cache, txn, funk_rec, prog_addr );
697+
fd_funk_rec_t * dup_rec = NULL;
698+
int push_ok = fd_progcache_push( cache, txn, funk_rec, prog_addr, &dup_rec );
685699

686700
/* Done modifying transaction */
687701

@@ -692,12 +706,11 @@ fd_progcache_invalidate( fd_progcache_t * cache,
692706
EVICTED AFTER PEEK? */
693707

694708
if( !push_ok ) {
695-
fd_progcache_rec_t const * other = fd_progcache_peek_exact( cache, xid, prog_addr );
696-
if( FD_UNLIKELY( !other ) ) {
697-
FD_LOG_CRIT(( "fd_progcache_push/fd_progcache_peek data race detected" ));
698-
}
709+
FD_TEST( dup_rec );
710+
fd_funk_val_flush( funk_rec, funk->alloc, funk->wksp );
711+
fd_funk_rec_pool_release( funk->rec_pool, funk_rec, 1 );
699712
cache->metrics->dup_insert_cnt++;
700-
return other;
713+
return fd_funk_val_const( dup_rec, funk->wksp );
701714
}
702715

703716
cache->metrics->invalidate_cnt++;

src/flamenco/progcache/test_progcache.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,7 @@ test_invalidate_dup( fd_wksp_t * wksp ) {
518518
FD_TEST( !rec2->executable );
519519
FD_TEST( fd_progcache_peek( env->progcache, &fork_b, &key, 0UL )==rec2 );
520520
FD_TEST( fd_progcache_peek( env->progcache, &fork_a, &key, 0UL )==rec );
521+
FD_TEST( fd_progcache_invalidate( env->progcache, &fork_b, &key, fork_b.ul[0] )==rec2 );
521522

522523
/* Create cache invalidation entry */
523524
fd_funk_txn_xid_t fork_c = { .ul = { 3UL, 2UL } };

0 commit comments

Comments
 (0)