From 4770ae710302c379076f9fc9735d66f947c7c20b Mon Sep 17 00:00:00 2001 From: Yufeng Zhou Date: Tue, 3 Mar 2026 02:52:20 +0000 Subject: [PATCH] replay: eviction fix --- src/discof/replay/fd_replay_tile.c | 3 +-- src/flamenco/accdb/fd_accdb_admin_v1.c | 1 - src/flamenco/accdb/fd_accdb_admin_v2.c | 7 ++++-- src/flamenco/progcache/fd_progcache_admin.c | 1 - src/flamenco/runtime/fd_bank.c | 20 +++++++++++++++- src/flamenco/runtime/fd_bank.h | 16 +++++++++++-- src/flamenco/runtime/test_bank.c | 26 ++++++++++----------- 7 files changed, 52 insertions(+), 22 deletions(-) diff --git a/src/discof/replay/fd_replay_tile.c b/src/discof/replay/fd_replay_tile.c index e1e6020e496..653172e74e4 100644 --- a/src/discof/replay/fd_replay_tile.c +++ b/src/discof/replay/fd_replay_tile.c @@ -2153,8 +2153,7 @@ after_credit( fd_replay_tile_t * ctx, return; } - if( FD_UNLIKELY( fd_banks_prune_dead_banks( ctx->banks ) ) ) { - // FIXME: anything pruned from banks should also be pruned from txncache and accdb + if( FD_UNLIKELY( fd_banks_prune_dead_banks( ctx->banks, ctx->txncache, ctx->accdb_admin, ctx->progcache_admin ) ) ) { *charge_busy = 1; *opt_poll_in = 0; return; diff --git a/src/flamenco/accdb/fd_accdb_admin_v1.c b/src/flamenco/accdb/fd_accdb_admin_v1.c index dd1a03e3bfb..fb0f7618eba 100644 --- a/src/flamenco/accdb/fd_accdb_admin_v1.c +++ b/src/flamenco/accdb/fd_accdb_admin_v1.c @@ -248,7 +248,6 @@ fd_accdb_v1_cancel( fd_accdb_admin_t * accdb_, } fd_funk_txn_t * txn = fd_funk_txn_map_query_ele( query ); - fd_accdb_txn_cancel_next_list( accdb, txn ); fd_accdb_txn_cancel_tree( accdb, txn ); } diff --git a/src/flamenco/accdb/fd_accdb_admin_v2.c b/src/flamenco/accdb/fd_accdb_admin_v2.c index 30c20cb07f1..46dcfde4aaf 100644 --- a/src/flamenco/accdb/fd_accdb_admin_v2.c +++ b/src/flamenco/accdb/fd_accdb_admin_v2.c @@ -81,9 +81,12 @@ fd_accdb_v2_attach_child( fd_accdb_admin_t * admin_, } void -fd_accdb_v2_cancel( fd_accdb_admin_t * admin, +fd_accdb_v2_cancel( fd_accdb_admin_t * admin_, fd_funk_txn_xid_t const * xid ) { - fd_accdb_v1_cancel( admin, xid ); + fd_accdb_admin_v2_t * admin = downcast( admin_ ); + admin->base.accdb_type = FD_ACCDB_TYPE_V1; + fd_accdb_v1_cancel( admin_, xid ); + admin->base.accdb_type = FD_ACCDB_TYPE_V2; } static void diff --git a/src/flamenco/progcache/fd_progcache_admin.c b/src/flamenco/progcache/fd_progcache_admin.c index 859a287ba00..f8a26673dac 100644 --- a/src/flamenco/progcache/fd_progcache_admin.c +++ b/src/flamenco/progcache/fd_progcache_admin.c @@ -207,7 +207,6 @@ fd_progcache_txn_cancel( fd_progcache_admin_t * cache, } fd_funk_txn_t * txn = fd_funk_txn_map_query_ele( query ); - fd_progcache_txn_cancel_next_list( cache, txn ); fd_progcache_txn_cancel_tree( cache, txn ); } diff --git a/src/flamenco/runtime/fd_bank.c b/src/flamenco/runtime/fd_bank.c index 908e38978ed..7fe3b7b0d86 100644 --- a/src/flamenco/runtime/fd_bank.c +++ b/src/flamenco/runtime/fd_bank.c @@ -1,6 +1,9 @@ #include "fd_bank.h" #include "fd_runtime_const.h" #include "../rewards/fd_stake_rewards.h" +#include "fd_txncache.h" +#include "../accdb/fd_accdb_admin.h" +#include "../progcache/fd_progcache_admin.h" ulong fd_bank_align( void ) { @@ -1034,7 +1037,10 @@ fd_banks_mark_bank_dead( fd_banks_t * banks, } int -fd_banks_prune_dead_banks( fd_banks_t * banks ) { +fd_banks_prune_dead_banks( fd_banks_t * banks, + fd_txncache_t * txncache, + fd_accdb_admin_t * accdb_admin, + fd_progcache_admin_t * progcache_admin ) { fd_rwlock_write( &banks->locks->banks_lock ); int any_pruned = 0; @@ -1054,6 +1060,18 @@ fd_banks_prune_dead_banks( fd_banks_t * banks ) { FD_LOG_DEBUG(( "pruning dead bank (idx=%lu)", bank->idx )); + if( txncache && bank->flags&FD_BANK_FLAGS_REPLAYABLE ) { + fd_txncache_cancel_fork( txncache, bank->txncache_fork_id ); + + fd_bank_t bank_l[1]; + if( FD_UNLIKELY( !fd_banks_bank_query( bank_l, banks, bank->idx ) ) ) { + FD_LOG_CRIT(( "invariant violation: bank is NULL for bank index %lu", bank->idx )); + } + fd_funk_txn_xid_t xid = { .ul = { fd_bank_slot_get( bank_l ), bank->idx } }; + fd_accdb_cancel( accdb_admin, &xid ); + fd_progcache_txn_cancel( progcache_admin, &xid ); + } + bank->flags = 0UL; /* There are a few cases to consider: diff --git a/src/flamenco/runtime/fd_bank.h b/src/flamenco/runtime/fd_bank.h index 8bc06e721f5..821e92581b8 100644 --- a/src/flamenco/runtime/fd_bank.h +++ b/src/flamenco/runtime/fd_bank.h @@ -12,6 +12,15 @@ #include "../../ballet/lthash/fd_lthash.h" #include "fd_txncache_shmem.h" +struct fd_txncache_private; +typedef struct fd_txncache_private fd_txncache_t; + +struct fd_accdb_admin; +typedef struct fd_accdb_admin fd_accdb_admin_t; + +struct fd_progcache_admin; +typedef struct fd_progcache_admin fd_progcache_admin_t; + FD_PROTOTYPES_BEGIN #define FD_BANKS_MAGIC (0XF17EDA2C7EBA2450) /* FIREDANCER BANKS V0 */ @@ -197,7 +206,7 @@ FD_PROTOTYPES_BEGIN fd_banks_mark_bank_dead( banks, dead_bank_idx ); To actually prune away any dead banks, the caller should call: - fd_banks_prune_dead_banks( banks ) + fd_banks_prune_dead_banks( banks, txncache, accdb_admin, progcache_admin ) The locks and data used by an fd_bank_t or an fd_banks_t are stored as separate objects. The locks are stored in an fd_banks_locks_t struct @@ -934,7 +943,10 @@ fd_banks_mark_bank_dead( fd_banks_t * banks, and 0 otherwise. */ int -fd_banks_prune_dead_banks( fd_banks_t * banks ); +fd_banks_prune_dead_banks( fd_banks_t * banks, + fd_txncache_t * txncache, + fd_accdb_admin_t * accdb_admin, + fd_progcache_admin_t * progcache_admin ); /* fd_banks_mark_bank_frozen marks the current bank as frozen. This should be done when the bank is no longer being updated: it should be diff --git a/src/flamenco/runtime/test_bank.c b/src/flamenco/runtime/test_bank.c index 9ddaf4afcf3..acee5c68561 100644 --- a/src/flamenco/runtime/test_bank.c +++ b/src/flamenco/runtime/test_bank.c @@ -291,7 +291,7 @@ test_bank_dead_eviction( void * mem ) { bank_P->data->refcnt = 0UL; /* P(0) */ FD_TEST( fd_banks_pool_used( bank_data_pool )==1UL ); - FD_TEST( !fd_banks_prune_dead_banks( banks ) ); + FD_TEST( !fd_banks_prune_dead_banks( banks, NULL, NULL, NULL ) ); FD_TEST( fd_banks_pool_used( bank_data_pool )==1UL ); /* Case: isolated dead bank that gets pruned. */ @@ -301,7 +301,7 @@ test_bank_dead_eviction( void * mem ) { FD_TEST( fd_banks_clone_from_parent( bank_D, banks, bank_D->data->idx ) ); FD_TEST( fd_banks_pool_used( bank_data_pool )==2UL ); - FD_TEST( !fd_banks_prune_dead_banks( banks ) ); + FD_TEST( !fd_banks_prune_dead_banks( banks, NULL, NULL, NULL ) ); FD_TEST( fd_banks_pool_used( bank_data_pool )==2UL ); fd_banks_mark_bank_frozen( banks, bank_D ); @@ -309,7 +309,7 @@ test_bank_dead_eviction( void * mem ) { FD_TEST( fd_banks_pool_used( bank_data_pool )==2UL ); FD_TEST( bank_D->data->flags&FD_BANK_FLAGS_DEAD ); - FD_TEST( fd_banks_prune_dead_banks( banks ) ); + FD_TEST( fd_banks_prune_dead_banks( banks, NULL, NULL, NULL ) ); FD_TEST( fd_banks_pool_used( bank_data_pool )==1UL ); /* Case: multiple isolated dead banks get pruned at once. */ @@ -318,7 +318,7 @@ test_bank_dead_eviction( void * mem ) { FD_TEST( fd_banks_pool_used( bank_data_pool )==2UL ); FD_TEST( fd_banks_clone_from_parent( bank_C, banks, bank_C->data->idx ) ); FD_TEST( fd_banks_pool_used( bank_data_pool )==2UL ); - FD_TEST( !fd_banks_prune_dead_banks( banks ) ); + FD_TEST( !fd_banks_prune_dead_banks( banks, NULL, NULL, NULL ) ); FD_TEST( fd_banks_pool_used( bank_data_pool )==2UL ); fd_banks_mark_bank_frozen( banks, bank_C ); @@ -327,7 +327,7 @@ test_bank_dead_eviction( void * mem ) { FD_TEST( fd_banks_pool_used( bank_data_pool )==3UL ); FD_TEST( fd_banks_clone_from_parent( bank_R, banks, bank_R->data->idx ) ); FD_TEST( fd_banks_pool_used( bank_data_pool )==3UL ); - FD_TEST( !fd_banks_prune_dead_banks( banks ) ); + FD_TEST( !fd_banks_prune_dead_banks( banks, NULL, NULL, NULL ) ); FD_TEST( fd_banks_pool_used( bank_data_pool )==3UL ); fd_bank_t bank_Y[1]; @@ -335,7 +335,7 @@ test_bank_dead_eviction( void * mem ) { FD_TEST( fd_banks_pool_used( bank_data_pool )==4UL ); FD_TEST( fd_banks_clone_from_parent( bank_Y, banks, bank_Y->data->idx ) ); FD_TEST( fd_banks_pool_used( bank_data_pool )==4UL ); - FD_TEST( !fd_banks_prune_dead_banks( banks ) ); + FD_TEST( !fd_banks_prune_dead_banks( banks, NULL, NULL, NULL ) ); FD_TEST( fd_banks_pool_used( bank_data_pool )==4UL ); fd_bank_t bank_Z[1]; @@ -343,12 +343,12 @@ test_bank_dead_eviction( void * mem ) { FD_TEST( fd_banks_pool_used( bank_data_pool )==5UL ); FD_TEST( fd_banks_clone_from_parent( bank_Z, banks, bank_Z->data->idx ) ); FD_TEST( fd_banks_pool_used( bank_data_pool )==5UL ); - FD_TEST( !fd_banks_prune_dead_banks( banks ) ); + FD_TEST( !fd_banks_prune_dead_banks( banks, NULL, NULL, NULL ) ); FD_TEST( fd_banks_pool_used( bank_data_pool )==5UL ); fd_banks_mark_bank_dead( banks, bank_Y->data->idx ); fd_banks_mark_bank_dead( banks, bank_Z->data->idx ); - FD_TEST( fd_banks_prune_dead_banks( banks ) ); + FD_TEST( fd_banks_prune_dead_banks( banks, NULL, NULL, NULL ) ); FD_TEST( fd_banks_pool_used( bank_data_pool )==3UL ); /* Case: dead banks that are siblings of non pruned banks. Make sure @@ -370,7 +370,7 @@ test_bank_dead_eviction( void * mem ) { fd_banks_mark_bank_dead( banks, bank_W->data->idx ); FD_TEST( bank_G->data->sibling_idx==bank_W->data->idx ); - FD_TEST( fd_banks_prune_dead_banks( banks ) ); + FD_TEST( fd_banks_prune_dead_banks( banks, NULL, NULL, NULL ) ); FD_TEST( fd_banks_pool_used( bank_data_pool )==4UL ); FD_TEST( bank_G->data->sibling_idx==ULONG_MAX ); @@ -386,7 +386,7 @@ test_bank_dead_eviction( void * mem ) { fd_banks_mark_bank_dead( banks, bank_W->data->idx ); FD_TEST( bank_G->data->sibling_idx==bank_W->data->idx ); - FD_TEST( fd_banks_prune_dead_banks( banks ) ); + FD_TEST( fd_banks_prune_dead_banks( banks, NULL, NULL, NULL ) ); FD_TEST( fd_banks_pool_used( bank_data_pool )==5UL ); FD_TEST( bank_G->data->sibling_idx!=ULONG_MAX ); FD_TEST( bank_G->data->sibling_idx==bank_I->data->idx ); @@ -409,7 +409,7 @@ test_bank_dead_eviction( void * mem ) { FD_TEST( fd_banks_bank_query( bank_query, banks, bank_I->data->idx ) ); FD_TEST( !fd_banks_bank_query( bank_query, banks, bank_Z->data->idx ) ); - FD_TEST( !fd_banks_prune_dead_banks( banks ) ); + FD_TEST( !fd_banks_prune_dead_banks( banks, NULL, NULL, NULL ) ); /* Case: don't prune dead banks if there is an outstanding reference to them. */ @@ -422,11 +422,11 @@ test_bank_dead_eviction( void * mem ) { bank_D->data->refcnt = 1UL; fd_banks_mark_bank_dead( banks, bank_D->data->idx ); - FD_TEST( fd_banks_prune_dead_banks( banks ) ); + FD_TEST( fd_banks_prune_dead_banks( banks, NULL, NULL, NULL ) ); FD_TEST( fd_banks_pool_used( bank_data_pool )==4UL ); bank_D->data->refcnt = 0UL; - FD_TEST( fd_banks_prune_dead_banks( banks ) ); + FD_TEST( fd_banks_prune_dead_banks( banks, NULL, NULL, NULL ) ); FD_TEST( fd_banks_pool_used( bank_data_pool )==3UL ); /* Case: dead bank is the left-most child of the parent. */