Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions book/api/metrics-generated.md
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,7 @@
| <span class="metrics-name">replay_&#8203;accdb_&#8203;reverted</span> | counter | Number of account database records reverted |
| <span class="metrics-name">replay_&#8203;accdb_&#8203;rooted</span> | counter | Number of account database entries rooted |
| <span class="metrics-name">replay_&#8203;accdb_&#8203;gc_&#8203;root</span> | counter | Number of account database entries garbage collected |
| <span class="metrics-name">replay_&#8203;accdb_&#8203;reclaimed</span> | counter | Number of account database entries reclaimed (deletion rooted) |

</div>

Expand Down
1 change: 1 addition & 0 deletions src/disco/metrics/generated/fd_metrics_replay.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,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 ),
};
8 changes: 7 additions & 1 deletion src/disco/metrics/generated/fd_metrics_replay.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,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 (29UL)
#define FD_METRICS_COUNTER_REPLAY_ACCDB_RECLAIMED_OFF (141UL)
#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 (30UL)
extern const fd_metrics_meta_t FD_METRICS_REPLAY[FD_METRICS_REPLAY_TOTAL];

#endif /* HEADER_fd_src_disco_metrics_generated_fd_metrics_replay_h */
1 change: 1 addition & 0 deletions src/disco/metrics/metrics.xml
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,7 @@ metric introduced.
<counter name="AccdbReverted" summary="Number of account database records reverted" />
<counter name="AccdbRooted" summary="Number of account database entries rooted" />
<counter name="AccdbGcRoot" summary="Number of account database entries garbage collected" />
<counter name="AccdbReclaimed" summary="Number of account database entries reclaimed (deletion rooted)" />
</tile>

<tile name="storei">
Expand Down
9 changes: 5 additions & 4 deletions src/discof/replay/fd_replay_tile.c
Original file line number Diff line number Diff line change
Expand Up @@ -498,10 +498,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
Expand Down
55 changes: 48 additions & 7 deletions src/flamenco/accdb/fd_accdb_admin.c
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -214,6 +215,36 @@ 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 ) ));
FD_COMPILER_MFENCE();

/* 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. */

Expand All @@ -227,7 +258,8 @@ 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 ) ));
FD_COMPILER_MFENCE();

/* Phase 2: Invalidate record */

Expand Down Expand Up @@ -257,6 +289,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 ];

Expand All @@ -266,13 +299,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 */
}
Expand Down
7 changes: 4 additions & 3 deletions src/flamenco/accdb/fd_accdb_admin.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down
20 changes: 0 additions & 20 deletions src/flamenco/accdb/fd_accdb_ref.h
Original file line number Diff line number Diff line change
Expand Up @@ -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. */

Expand Down
4 changes: 2 additions & 2 deletions src/flamenco/progcache/fd_prog_load.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ fd_get_executable_program_content_for_upgradeable_loader( fd_funk_t const *
fd_pubkey_t * programdata_address = &program_account_state->inner.program.programdata_address;

fd_account_meta_t const * meta = fd_funk_get_acc_meta_readonly(
funk, xid, programdata_address, NULL, NULL, out_xid );
funk, xid, programdata_address, out_xid );
if( FD_UNLIKELY( !meta ) ) return NULL;
fd_txn_account_t _rec[1];
fd_txn_account_t * programdata_acc = fd_txn_account_join( fd_txn_account_new( _rec, programdata_address, (void *)meta, 0 ) );
Expand Down Expand Up @@ -114,7 +114,7 @@ fd_prog_load_elf( fd_accdb_user_t * accdb,
fd_funk_txn_xid_t _out_xid;
if( !out_xid ) out_xid = &_out_xid;
fd_account_meta_t const * meta = fd_funk_get_acc_meta_readonly(
funk, xid, &prog_addr, NULL, NULL, out_xid );
funk, xid, &prog_addr, out_xid );
if( FD_UNLIKELY( !meta ) ) return NULL;
fd_txn_account_t _rec[1];
fd_txn_account_t * rec = fd_txn_account_join( fd_txn_account_new( _rec, &prog_addr, (void *)meta, 0 ) );
Expand Down
1 change: 1 addition & 0 deletions src/flamenco/progcache/fd_progcache_admin.c
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ fd_progcache_gc_root( fd_progcache_admin_t * cache,
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 ) ));
FD_COMPILER_MFENCE();

/* Phase 2: Invalidate record */

Expand Down
39 changes: 13 additions & 26 deletions src/flamenco/runtime/fd_acc_mgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,52 +5,39 @@ fd_account_meta_t const *
fd_funk_get_acc_meta_readonly( fd_funk_t const * funk,
fd_funk_txn_xid_t const * xid,
fd_pubkey_t const * pubkey,
fd_funk_rec_t const ** orec,
int * opt_err,
fd_funk_txn_xid_t * out_xid ) {
fd_funk_rec_key_t id = fd_funk_acc_key( pubkey );

/* When we access this pointer later on in the execution pipeline, we assume that
nothing else will change that account. If the account is writable in the solana txn,
then we copy the data. If the account is read-only, we do not. This is safe because of
the read-write locks that the solana transaction holds on the account. */
for( ; ; ) {

for(;;) {

/* Locate the account record */

fd_funk_rec_query_t query[1];
fd_funk_rec_t const * rec = fd_funk_rec_query_try_global( funk, xid, &id, out_xid, query );

if( FD_UNLIKELY( !rec ) ) {
fd_int_store_if( !!opt_err, opt_err, FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT );
return NULL;
}
if( NULL != orec )
*orec = rec;

void const * raw = fd_funk_val( rec, fd_funk_wksp( funk ) );
/* Read account balance */

void const * raw = fd_funk_val( rec, fd_funk_wksp( funk ) );
fd_account_meta_t const * metadata = fd_type_pun_const( raw );
if( FD_UNLIKELY( metadata->lamports==0UL ) ) {
fd_int_store_if( !!opt_err, opt_err, FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT );
if( NULL != orec ) *orec = NULL;
ulong const lamports = metadata->lamports;
if( FD_UNLIKELY( !lamports ) ) {
/* This account is awaiting deletion */
return NULL;
}
fd_int_store_if( !!opt_err, opt_err, FD_ACC_MGR_SUCCESS );
return metadata;

}
/* Recover from overruns (e.g. account rooted) */

/* unreachable */
return NULL;
}
if( FD_LIKELY( fd_funk_rec_map_query_test( query )==FD_MAP_SUCCESS ) ) {
return metadata;
}

FD_FN_CONST char const *
fd_acc_mgr_strerror( int err ) {
switch( err ) {
case FD_ACC_MGR_SUCCESS:
return "success";
case FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT:
return "unknown account";
default:
return "unknown";
}
}
20 changes: 1 addition & 19 deletions src/flamenco/runtime/fd_acc_mgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,22 +112,14 @@ fd_funk_acc_key( fd_pubkey_t const * pubkey ) {
On success:
- loads the account data into in-memory cache
- returns a pointer to it in the caller's local address space
- if out_rec!=NULL, sets *out_rec to a pointer to the funk rec.
This handle is suitable as opt_con_rec for fd_funk_get_acc_meta_readonly.
- notably, leaves *opt_err untouched, even if opt_err!=NULL

First byte of returned pointer is first byte of fd_account_meta_t.
To find data region of account, add sizeof(fd_account_meta_t).

Lifetime of returned fd_funk_rec_t and account record pointers ends
when user calls modify_data for same account, or tranasction ends.

On failure, returns NULL, and sets *opt_err if opt_err!=NULL.
Reasons for error include
- account not found
- internal database or user error (out of memory, attempting to view
record which has an active modify_data handle, etc.)
- the account is a tombstone (0 lamports)
If the account was not found, returns NULL.

It is always wrong to cast return value to a non-const pointer.
Instead, use fd_funk_get_acc_meta_mutable to acquire a mutable handle.
Expand All @@ -142,18 +134,8 @@ fd_account_meta_t const *
fd_funk_get_acc_meta_readonly( fd_funk_t const * funk,
fd_funk_txn_xid_t const * xid,
fd_pubkey_t const * pubkey,
fd_funk_rec_t const ** orec,
int * opt_err,
fd_funk_txn_xid_t * xid_out );

/* fd_acc_mgr_strerror converts an fd_acc_mgr error code into a human
readable cstr. The lifetime of the returned pointer is infinite and
the call itself is thread safe. The returned pointer is always to a
non-NULL cstr. */

FD_FN_CONST char const *
fd_acc_mgr_strerror( int err );

FD_PROTOTYPES_END

#endif /* HEADER_fd_src_flamenco_runtime_fd_acc_mgr_h */
26 changes: 5 additions & 21 deletions src/flamenco/runtime/fd_core_bpf_migration.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,12 @@ tmp_account_read( fd_tmp_account_t * acc,
fd_funk_t * funk,
fd_funk_txn_xid_t const * xid,
fd_pubkey_t const * addr ) {
int opt_err = 0;
fd_account_meta_t const * meta = fd_funk_get_acc_meta_readonly(
funk,
xid,
addr,
NULL,
&opt_err,
NULL );
if( FD_UNLIKELY( opt_err!=FD_ACC_MGR_SUCCESS ) ) {
if( FD_LIKELY( opt_err==FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT ) ) return NULL;
FD_LOG_CRIT(( "fd_funk_get_acc_meta_readonly failed (%d)", opt_err ));
}
if( FD_LIKELY( !meta ) ) return NULL;
tmp_account_new( acc, meta->dlen );
acc->meta = *meta;
acc->addr = *addr;
Expand Down Expand Up @@ -136,19 +130,14 @@ target_builtin_new_checked( target_builtin_t * target_builtin,
break;
case FD_CORE_BPF_MIGRATION_TARGET_STATELESS: {
/* Program account should not exist */
int opt_err = 0;
fd_funk_get_acc_meta_readonly(
int progdata_exists = !!fd_funk_get_acc_meta_readonly(
funk,
xid,
program_address,
NULL,
&opt_err,
NULL );
if( opt_err==FD_ACC_MGR_SUCCESS ) {
if( progdata_exists ) {
/* CoreBpfMigrationError::AccountAlreadyExists(*program_address) */
return NULL;
} else if( opt_err!=FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT ) {
FD_LOG_ERR(( "database error: %d", opt_err ));
}
break;
}
Expand All @@ -164,19 +153,14 @@ target_builtin_new_checked( target_builtin_t * target_builtin,

do {
/* Program data account should not exist */
int opt_err = 0;
fd_funk_get_acc_meta_readonly(
int progdata_exists = !!fd_funk_get_acc_meta_readonly(
funk,
xid,
&program_data_address,
NULL,
&opt_err,
NULL );
if( opt_err==FD_ACC_MGR_SUCCESS ) {
if( progdata_exists ) {
/* CoreBpfMigrationError::AccountAlreadyExists(*program_address) */
return NULL;
} else if( opt_err!=FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT ) {
FD_LOG_ERR(( "database error: %d", opt_err ));
}
} while(0);

Expand Down
Loading
Loading