diff --git a/book/api/metrics-generated.md b/book/api/metrics-generated.md index 6e7ac2612b..16c8981024 100644 --- a/book/api/metrics-generated.md +++ b/book/api/metrics-generated.md @@ -541,6 +541,7 @@ | replay_​accdb_​reverted | counter | Number of account database records reverted | | replay_​accdb_​rooted | counter | Number of account database entries rooted | | replay_​accdb_​gc_​root | counter | Number of account database entries garbage collected | +| replay_​accdb_​reclaimed | counter | Number of account database entries reclaimed (deletion rooted) | diff --git a/src/disco/metrics/generated/fd_metrics_replay.c b/src/disco/metrics/generated/fd_metrics_replay.c index 83d3f42484..74e5ce9354 100644 --- a/src/disco/metrics/generated/fd_metrics_replay.c +++ b/src/disco/metrics/generated/fd_metrics_replay.c @@ -30,4 +30,5 @@ const fd_metrics_meta_t FD_METRICS_REPLAY[FD_METRICS_REPLAY_TOTAL] = { DECLARE_METRIC( REPLAY_ACCDB_REVERTED, COUNTER ), DECLARE_METRIC( REPLAY_ACCDB_ROOTED, COUNTER ), DECLARE_METRIC( REPLAY_ACCDB_GC_ROOT, COUNTER ), + DECLARE_METRIC( REPLAY_ACCDB_RECLAIMED, COUNTER ), }; diff --git a/src/disco/metrics/generated/fd_metrics_replay.h b/src/disco/metrics/generated/fd_metrics_replay.h index 47298e92e5..ffcd466ab3 100644 --- a/src/disco/metrics/generated/fd_metrics_replay.h +++ b/src/disco/metrics/generated/fd_metrics_replay.h @@ -186,7 +186,13 @@ #define FD_METRICS_COUNTER_REPLAY_ACCDB_GC_ROOT_DESC "Number of account database entries garbage collected" #define FD_METRICS_COUNTER_REPLAY_ACCDB_GC_ROOT_CVT (FD_METRICS_CONVERTER_NONE) -#define FD_METRICS_REPLAY_TOTAL (28UL) +#define FD_METRICS_COUNTER_REPLAY_ACCDB_RECLAIMED_OFF (140UL) +#define FD_METRICS_COUNTER_REPLAY_ACCDB_RECLAIMED_NAME "replay_accdb_reclaimed" +#define FD_METRICS_COUNTER_REPLAY_ACCDB_RECLAIMED_TYPE (FD_METRICS_TYPE_COUNTER) +#define FD_METRICS_COUNTER_REPLAY_ACCDB_RECLAIMED_DESC "Number of account database entries reclaimed (deletion rooted)" +#define FD_METRICS_COUNTER_REPLAY_ACCDB_RECLAIMED_CVT (FD_METRICS_CONVERTER_NONE) + +#define FD_METRICS_REPLAY_TOTAL (29UL) extern const fd_metrics_meta_t FD_METRICS_REPLAY[FD_METRICS_REPLAY_TOTAL]; #endif /* HEADER_fd_src_disco_metrics_generated_fd_metrics_replay_h */ diff --git a/src/disco/metrics/metrics.xml b/src/disco/metrics/metrics.xml index ba58bc91b9..4f3bfe0ee4 100644 --- a/src/disco/metrics/metrics.xml +++ b/src/disco/metrics/metrics.xml @@ -813,6 +813,7 @@ metric introduced. + diff --git a/src/discof/replay/fd_replay_tile.c b/src/discof/replay/fd_replay_tile.c index 0a5ae60ef6..576a5e9349 100644 --- a/src/discof/replay/fd_replay_tile.c +++ b/src/discof/replay/fd_replay_tile.c @@ -495,10 +495,11 @@ metrics_write( fd_replay_tile_t * ctx ) { FD_MCNT_SET( REPLAY, PROGCACHE_ROOTED, ctx->progcache_admin->metrics.root_cnt ); FD_MCNT_SET( REPLAY, PROGCACHE_GC_ROOT, ctx->progcache_admin->metrics.gc_root_cnt ); - FD_MCNT_SET( REPLAY, ACCDB_CREATED, ctx->accdb->base.created_cnt ); - FD_MCNT_SET( REPLAY, ACCDB_REVERTED, ctx->accdb_admin->metrics.revert_cnt ); - FD_MCNT_SET( REPLAY, ACCDB_ROOTED, ctx->accdb_admin->metrics.root_cnt ); - FD_MCNT_SET( REPLAY, ACCDB_GC_ROOT, ctx->accdb_admin->metrics.gc_root_cnt ); + FD_MCNT_SET( REPLAY, ACCDB_CREATED, ctx->accdb->base.created_cnt ); + FD_MCNT_SET( REPLAY, ACCDB_REVERTED, ctx->accdb_admin->metrics.revert_cnt ); + FD_MCNT_SET( REPLAY, ACCDB_ROOTED, ctx->accdb_admin->metrics.root_cnt ); + FD_MCNT_SET( REPLAY, ACCDB_GC_ROOT, ctx->accdb_admin->metrics.gc_root_cnt ); + FD_MCNT_SET( REPLAY, ACCDB_RECLAIMED, ctx->accdb_admin->metrics.reclaim_cnt ); } static inline ulong diff --git a/src/flamenco/accdb/fd_accdb_admin.c b/src/flamenco/accdb/fd_accdb_admin.c index ec3c072c14..9798348c63 100644 --- a/src/flamenco/accdb/fd_accdb_admin.c +++ b/src/flamenco/accdb/fd_accdb_admin.c @@ -1,4 +1,5 @@ #include "fd_accdb_admin.h" +#include "../fd_flamenco_base.h" fd_accdb_admin_t * fd_accdb_admin_join( fd_accdb_admin_t * ljoin, @@ -209,6 +210,35 @@ fd_accdb_cancel( fd_accdb_admin_t * accdb, fd_accdb_txn_cancel_tree( accdb, txn ); } +/* fd_accdb_chain_reclaim "reclaims" a zero-lamport account by removing + its underlying record. */ + +static void +fd_accdb_chain_reclaim( fd_accdb_admin_t * accdb, + fd_funk_rec_t * rec ) { + fd_funk_t * funk = accdb->funk; + + /* Phase 1: Remove record from map */ + + fd_funk_xid_key_pair_t pair = rec->pair; + fd_funk_rec_query_t query[1]; + int rm_err = fd_funk_rec_map_remove( funk->rec_map, &pair, NULL, query, FD_MAP_FLAG_BLOCKING ); + if( FD_UNLIKELY( rm_err!=FD_MAP_SUCCESS ) ) FD_LOG_CRIT(( "fd_funk_rec_map_remove failed (%i-%s)", rm_err, fd_map_strerror( rm_err ) )); + + /* Phase 2: Invalidate record */ + + fd_funk_rec_t * old_rec = query->ele; + memset( &old_rec->pair, 0, sizeof(fd_funk_xid_key_pair_t) ); + FD_COMPILER_MFENCE(); + + /* Phase 3: Free record */ + + old_rec->map_next = FD_FUNK_REC_IDX_NULL; + fd_funk_val_flush( old_rec, funk->alloc, funk->wksp ); + fd_funk_rec_pool_release( funk->rec_pool, old_rec, 1 ); + accdb->metrics.reclaim_cnt++; +} + /* fd_accdb_chain_gc_root cleans up a stale "rooted" version of a record. */ @@ -222,7 +252,7 @@ fd_accdb_chain_gc_root( fd_accdb_admin_t * accdb, fd_funk_rec_query_t query[1]; int rm_err = fd_funk_rec_map_remove( funk->rec_map, pair, NULL, query, FD_MAP_FLAG_BLOCKING ); if( rm_err==FD_MAP_ERR_KEY ) return; - if( FD_UNLIKELY( rm_err!=FD_MAP_SUCCESS ) ) FD_LOG_CRIT(( "fd_funk_rec_map_remove failed: %i-%s", rm_err, fd_map_strerror( rm_err ) )); + if( FD_UNLIKELY( rm_err!=FD_MAP_SUCCESS ) ) FD_LOG_CRIT(( "fd_funk_rec_map_remove failed (%i-%s)", rm_err, fd_map_strerror( rm_err ) )); /* Phase 2: Invalidate record */ @@ -252,6 +282,7 @@ fd_accdb_publish_recs( fd_accdb_admin_t * accdb, uint head = txn->rec_head_idx; txn->rec_head_idx = FD_FUNK_REC_IDX_NULL; txn->rec_tail_idx = FD_FUNK_REC_IDX_NULL; + fd_wksp_t * funk_wksp = accdb->funk->wksp; while( !fd_funk_rec_idx_is_null( head ) ) { fd_funk_rec_t * rec = &accdb->funk->rec_pool->ele[ head ]; @@ -261,13 +292,21 @@ fd_accdb_publish_recs( fd_accdb_admin_t * accdb, fd_funk_txn_xid_set_root( pair->xid ); fd_accdb_chain_gc_root( accdb, pair ); - /* Migrate record to root */ + /* Root or reclaim record */ uint next = rec->next_idx; - rec->prev_idx = FD_FUNK_REC_IDX_NULL; - rec->next_idx = FD_FUNK_REC_IDX_NULL; - fd_funk_txn_xid_t const root = { .ul = { ULONG_MAX, ULONG_MAX } }; - fd_funk_txn_xid_st_atomic( rec->pair.xid, &root ); - accdb->metrics.root_cnt++; + fd_account_meta_t const * meta = fd_funk_val( rec, funk_wksp ); + FD_CRIT( meta && rec->val_sz>=sizeof(fd_account_meta_t), "invalid funk record value" ); + if( FD_LIKELY( meta->lamports ) ) { + /* Migrate record to root */ + rec->prev_idx = FD_FUNK_REC_IDX_NULL; + rec->next_idx = FD_FUNK_REC_IDX_NULL; + fd_funk_txn_xid_t const root = { .ul = { ULONG_MAX, ULONG_MAX } }; + fd_funk_txn_xid_st_atomic( rec->pair.xid, &root ); + accdb->metrics.root_cnt++; + } else { + /* Remove record */ + fd_accdb_chain_reclaim( accdb, rec ); + } head = next; /* next record */ } diff --git a/src/flamenco/accdb/fd_accdb_admin.h b/src/flamenco/accdb/fd_accdb_admin.h index 24fe44891b..37adf1365c 100644 --- a/src/flamenco/accdb/fd_accdb_admin.h +++ b/src/flamenco/accdb/fd_accdb_admin.h @@ -7,9 +7,10 @@ struct fd_accdb_admin { fd_funk_t funk[1]; struct { - ulong root_cnt; - ulong gc_root_cnt; - ulong revert_cnt; + ulong root_cnt; /* moved to database root */ + ulong reclaim_cnt; /* 0 lamport account removed while rooting */ + ulong gc_root_cnt; /* stale rooted revisions removed while rooting */ + ulong revert_cnt; /* abandoned by consensus */ } metrics; }; diff --git a/src/flamenco/accdb/fd_accdb_ref.h b/src/flamenco/accdb/fd_accdb_ref.h index c2865c7ff8..a1fe53b26e 100644 --- a/src/flamenco/accdb/fd_accdb_ref.h +++ b/src/flamenco/accdb/fd_accdb_ref.h @@ -170,26 +170,6 @@ fd_accdb_ref_slot_set( fd_accdb_rw_t * rw, FD_PROTOTYPES_END -/* fd_accdb_guardr_t tracks a rwlock being held as read-only. - Destroying this guard object detaches the caller's thread from the - rwlock. */ - -struct fd_accbd_guardr { - fd_rwlock_t * rwlock; -}; - -typedef struct fd_accdb_guardr fd_accdb_guardr_t; - -/* fd_accdb_guardw_t tracks an rwlock being held exclusively. - Destroying this guard object detaches the caller's thread from the - lock. */ - -struct fd_accdb_guardw { - fd_rwlock_t * rwlock; -}; - -typedef struct fd_accdb_guardw fd_accdb_guardw_t; - /* fd_accdb_spec_t tracks a speculative access to a shared resource. Destroying this guard object marks the end of a speculative access. */