LCOV - code coverage report
Current view: top level - flamenco/accdb - fd_accdb.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 1 30 3.3 %
Date: 2026-08-15 04:34:25 Functions: 0 0 -

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_accdb_fd_accdb_h
       2             : #define HEADER_fd_src_flamenco_accdb_fd_accdb_h
       3             : 
       4             : #include "fd_accdb_base.h"
       5             : #include "fd_accdb_shmem.h"
       6             : 
       7             : /* The accdb is a fork aware database that can be queried to get the
       8             :    current state of any accounts as-of a given fork, and update them. */
       9             : 
      10       12600 : #define FD_ACCDB_ALIGN (128UL)
      11             : 
      12             : /* Well-known file descriptor numbers for the accounts database backing
      13             :    file.  Tiles inherit these from the parent process which dups the
      14             :    accounts file to these fds before fork+exec, so seccomp filters can
      15             :    pin syscalls to a fixed fd.  fd 123462 is reserved by XDP. */
      16             : 
      17           0 : #define FD_ACCDB_FD_RW (123461)
      18           0 : #define FD_ACCDB_FD_RO (123460)
      19             : 
      20             : struct fd_accdb_entry {
      21             :   uchar   pubkey[ 32UL ];
      22             :   uchar   owner[ 32UL ];
      23             :   ulong   lamports;
      24             :   int     executable;
      25             : 
      26             :   ulong   data_len;
      27             :   uchar * data;
      28             : 
      29             :   uchar   prior_owner[ 32UL ];
      30             :   ulong   prior_lamports;
      31             :   int     prior_executable;
      32             :   ulong   prior_data_len;
      33             :   uchar * prior_data;
      34             : 
      35             :   int     commit;
      36             :   int     pd_write;
      37             : 
      38             :   int     _writable;
      39             :   int     _overwrite;
      40             : 
      41             :   ushort  _fork_id;
      42             :   uint    _generation;
      43             :   ulong   _acc_map_idx;
      44             : 
      45             :   ulong   _original_size_class;
      46             :   ulong   _original_cache_idx;
      47             : 
      48             :   struct {
      49             :     ulong destination_cache_idx[ 8UL ];
      50             :   } _write;
      51             : };
      52             : 
      53             : typedef struct fd_accdb_entry fd_acc_t;
      54             : 
      55             : FD_PROTOTYPES_BEGIN
      56             : 
      57             : FD_FN_CONST ulong
      58             : fd_accdb_align( void );
      59             : 
      60             : FD_FN_CONST ulong
      61             : fd_accdb_footprint( ulong max_live_slots );
      62             : 
      63             : /* fd_accdb_new constructs the local joiner state for an accdb writer
      64             :    (or compaction tile).  fd is an O_RDWR fd of the on-disk file.
      65             : 
      66             :    external_epoch_cnt and external_epoch_slots provide a list of
      67             :    additional epoch publish slots to scan during compaction's
      68             :    deferred-free reclamation.  These point at memory owned by other
      69             :    processes (typically the per-tile fseq of read-only consumers like
      70             :    the rpc tile), mapped read-only into this joiner's address space.
      71             :    Each *external_epoch_slots[i] is updated by the owning RO joiner
      72             :    on each epoch-protected operation (and reset to ULONG_MAX when
      73             :    idle), and is used by this joiner's compaction scan to determine
      74             :    when on-disk partitions can be safely reclaimed.
      75             : 
      76             :    For joiners that do not need to track external RO consumers (i.e.
      77             :    any joiner that is not the compaction tile, or a writer-only
      78             :    topology), pass external_epoch_cnt=0 and external_epoch_slots=NULL.
      79             :    The pointer array is borrowed and must remain valid for the
      80             :    lifetime of the join. */
      81             : 
      82             : void *
      83             : fd_accdb_new( void *              ljoin,
      84             :               fd_accdb_shmem_t *  shmem,
      85             :               int                 fd,
      86             :               ulong               external_epoch_cnt,
      87             :               ulong const **      external_epoch_slots );
      88             : 
      89             : fd_accdb_t *
      90             : fd_accdb_join( void * shaccdb );
      91             : 
      92             : /* fd_accdb_join_readonly is the read-only counterpart of fd_accdb_new +
      93             :    fd_accdb_join.  shmem_ro may point into a read-only mapping of the
      94             :    shmem region; the function will not write to it.  my_epoch_slot_rw
      95             :    must point at a ulong owned by this joiner that it can write to
      96             :    (typically a private per-tile fseq that the accdb tile maps read-only
      97             :    and passes through external_epoch_slots[] in fd_accdb_new).  fd_ro
      98             :    must be opened O_RDONLY on the same file the writer joiner opened RW.
      99             : 
     100             :    The joiner publishes its current epoch into *my_epoch_slot_rw on
     101             :    entry to each epoch-protected operation (and resets to ULONG_MAX on
     102             :    exit).  The accdb tile's compaction scan observes this slot via its
     103             :    external_epoch_slots[] pointer and defers partition reclamation
     104             :    accordingly, the same way it does for in-shmem joiner_epochs[].
     105             : 
     106             :    Only fd_accdb_read_one_nocache, fd_accdb_exists, and
     107             :    fd_accdb_lamports are supported on a readonly join; any other API is
     108             :    undefined behavior. */
     109             : 
     110             : fd_accdb_t *
     111             : fd_accdb_join_readonly( void *             ljoin,
     112             :                         fd_accdb_shmem_t * shmem_ro,
     113             :                         ulong *            my_epoch_slot_rw,
     114             :                         int                fd_ro );
     115             : 
     116             : /* fd_accdb_snapshot_load_{begin,end} toggle a mode on this writer
     117             :    joiner that causes layer-0 partition handoffs to backfill tiering
     118             :    for older snapshot-loaded partitions.  Specifically, when a new
     119             :    partition P is opened at layer 0, the partition at P-2 is retiered
     120             :    to Warm (layer 1) and the partition at P-3 is retiered to Cold
     121             :    (layer 2).  This compensates for the fact that snapshot-loaded
     122             :    accounts never get a second write and therefore never get promoted
     123             :    by normal compaction-driven tiering.
     124             : 
     125             :    The snapshot loader has exclusive write access to acc_pool. */
     126             : 
     127             : void
     128             : fd_accdb_snapshot_load_begin( fd_accdb_t * accdb );
     129             : 
     130             : void
     131             : fd_accdb_snapshot_load_end( fd_accdb_t * accdb );
     132             : 
     133             : /* fd_accdb_snapshot_recover_delta appends into the accdb delta set the
     134             :    accounts modified at fork_id.
     135             : 
     136             :    This is intended to be used after booting off an incremental snapshot
     137             :    and allows the validator to create additional incremental snaps.
     138             : 
     139             :    Not thread safe: assumes no one but the calling thread is accessing
     140             :    accdb deltas.  Returns 0 on success, -1 if the delta map is too small. */
     141             : 
     142             : int
     143             : fd_accdb_snapshot_recover_delta( fd_accdb_t *       accdb,
     144             :                                  fd_accdb_fork_id_t fork_id );
     145             : 
     146             : /* fd_accdb_snapshot_recovery_t captures layer-0 write head metadata.
     147             :    Used by fd_accdb_snapshot_{save,revert}_whead to save and restore
     148             :    accdb state across an incremental snapshot attempt. */
     149             : 
     150             : struct fd_accdb_snapshot_recovery {
     151             :   ulong whead_val;             /* whead[0].val */
     152             :   int   has_partition;         /* has_partition[0] */
     153             :   ulong partition_max;         /* partition_max */
     154             :   ulong disk_current_bytes;    /* disk_current_bytes metric */
     155             :   ulong savepoint_bytes_freed; /* bytes_freed of the save-point partition */
     156             : };
     157             : 
     158             : typedef struct fd_accdb_snapshot_recovery fd_accdb_snapshot_recovery_t;
     159             : 
     160             : /* fd_accdb_snapshot_save_whead captures the current layer-0 write head,
     161             :    partition state, and disk_current_bytes metric into the provided
     162             :    recovery struct.  Also captures the save-point partition's
     163             :    bytes_freed. */
     164             : 
     165             : void
     166             : fd_accdb_snapshot_save_whead( fd_accdb_t *                   accdb,
     167             :                               fd_accdb_snapshot_recovery_t * out );
     168             : 
     169             : /* fd_accdb_snapshot_revert_whead restores the layer-0 write head to a
     170             :    previously saved position.
     171             : 
     172             :    It internally waits for the pending background purge command to
     173             :    complete on T2 before releasing partitions, so the caller does not
     174             :    need to insert a separate wait_cmd barrier.
     175             : 
     176             :    Previously allocated partitions (with indices in the range
     177             :    [saved_partition_max, current partition_max)) are released back
     178             :    to the partition pool.  disk_current_bytes is restored to the saved
     179             :    value rather than computed per-partition, and the save-point
     180             :    partition's bytes_freed and write_offset are reset. */
     181             : 
     182             : void
     183             : fd_accdb_snapshot_revert_whead( fd_accdb_t *                         accdb,
     184             :                                 fd_accdb_snapshot_recovery_t const * recover );
     185             : 
     186             : /* fd_accdb_attach_child allocates a new fork as a child of
     187             :    parent_fork_id and returns the new fork's id.  This must be done
     188             :    any time a new fork is being inserted into the accounts database,
     189             :    so that the accounts database can maintain ancestry information
     190             :    in order to support queries correctly.
     191             : 
     192             :    To create the initial root fork, pass a sentinel value with
     193             :    val==USHORT_MAX as parent_fork_id.  This must be done exactly
     194             :    once, before any other fork operations.
     195             : 
     196             :    For non-root forks, parent_fork_id must refer to a fork that has
     197             :    already been attached.  The ancestry must form a tree and it is
     198             :    undefined behavior to create cycles.
     199             : 
     200             :    If the fork pool is full but contains deferred forks, this call
     201             :    blocks until reader epochs drain and a deferred slot can be reused.
     202             :    The caller should never call this function unless there are either
     203             :    free fork ids or deferred ones. */
     204             : 
     205             : fd_accdb_fork_id_t
     206             : fd_accdb_attach_child( fd_accdb_t *       accdb,
     207             :                        fd_accdb_fork_id_t parent_fork_id );
     208             : 
     209             : /* fd_accdb_advance_root advances the root of the accounts database to
     210             :    the given fork_id.  fork_id must be a direct child of the current
     211             :    root (i.e. fork->parent_id equals the current root_fork_id).
     212             : 
     213             :    Any competing sibling forks (and their entire subtrees) are removed.
     214             :    For accounts updated on the newly rooted fork, any older versions on
     215             :    ancestor forks are tombstoned for later compaction.  After this call
     216             :    the old root fork slot is freed and fork_id becomes the new root.
     217             : 
     218             :    IMPORTANT: The caller must guarantee that all outstanding
     219             :    acquire/release pairs on every sibling of fork_id (and their entire
     220             :    subtrees) have completed before calling advance_root.  advance_root
     221             :    implicitly purges those sibling subtrees, which frees their fork pool
     222             :    slots for recycling.
     223             : 
     224             :    Once a fork is rooted, its generation becomes the new
     225             :    root_generation.  Concurrent acquires that observe the new root will
     226             :    use the generation fast path (generation <= root_generation) for all
     227             :    accounts from that fork and its ancestors, bypassing descends_set
     228             :    entirely.  This is what makes fork pool slot recycling safe: by the
     229             :    time a slot is freed and reusable, no reader will ever consult
     230             :    descends_set for the old fork_id. */
     231             : 
     232             : void
     233             : fd_accdb_advance_root( fd_accdb_t *       accdb,
     234             :                        fd_accdb_fork_id_t fork_id );
     235             : 
     236             : /* fd_accdb_purge removes the provided fork and all of its descendants
     237             :    from the accounts database.  This is an extremely rare operation,
     238             :    used to handle cases where a leader equivocated and produced two
     239             :    competing blocks for the same slot.
     240             : 
     241             :    All accounts written on the purged fork and any child or
     242             :    grandchild forks are removed from the index, and their disk
     243             :    space is freed for compaction.  The ancestry information for all
     244             :    purged forks is also removed.
     245             : 
     246             :    IMPORTANT: The caller must guarantee that all outstanding
     247             :    acquire/release pairs on the purged fork and every descendant
     248             :    have completed before calling purge.  The same fork pool slot
     249             :    recycling hazard described for advance_root applies here. */
     250             : 
     251             : void
     252             : fd_accdb_purge( fd_accdb_t *       accdb,
     253             :                 fd_accdb_fork_id_t fork_id );
     254             : 
     255             : /* fd_accdb_acquire brings all of the requested accounts as-of the given
     256             :    fork_idx into the cache, and refcnts them in the cache so they cannot
     257             :    be evicted until later released.
     258             : 
     259             :    fork_idx is the fork index from replay to query as-of, and must exist
     260             :    for the entire duration of the acquire call, meaning, whoever is
     261             :    acquiring must have a refcnt on the bank corresponding to fork_idx,
     262             :    and not release it until after the accounts are acquired.  It is safe
     263             :    to release the bank after the acquire call returns, and this will not
     264             :    cause the acquired accounts to be evicted from the cache.
     265             : 
     266             :    The refcnt does not have to be on the bank of fork_idx itself: a
     267             :    refcnt on a live child bank of fork_idx also suffices.  This is the
     268             :    executor's pattern, it holds a refcnt on the executing child bank
     269             :    and read-only acquires implicit programdata on that bank's (frozen)
     270             :    parent fork.  It works because a fork with a live (refcnt>0) child
     271             :    bank can be neither advanced-past nor purged, so fork_idx cannot be
     272             :    recycled out from under the acquire.  advance_root(fork_idx) itself
     273             :    (rooting the queried fork) IS permitted concurrently with a read-only
     274             :    acquire on fork_idx (see the THREADING MODEL section); what remains
     275             :    forbidden is advancing PAST fork_idx or purging it while any acquire
     276             :    on it is outstanding.
     277             : 
     278             :    pubkeys_cnt is the number of accounts to acquire, and pubkeys is an
     279             :    array of pointers to the 32-byte pubkeys of the accounts to acquire.
     280             :    writable is an array of flags indicating whether each corresponding
     281             :    account in pubkeys is being acquired for read (0) or write (1).
     282             :    Writes provide a temporary buffer of 10MiB in all cases, which the
     283             :    caller can use for staging changes to the data, and this allows
     284             :    account resizing, or cancelling of any data written (for example if a
     285             :    transaction fails) without needing to restore it.  If an account is
     286             :    acquired for write, the caller must set the commit bit on the acc
     287             :    to non-zero to have the changes written back to the database on
     288             :    release, or leave it at zero to discard the changes.  The commit bit
     289             :    must be set even if only the metadata has changed.
     290             : 
     291             :    IMPORTANT: The caller must guarantee that for any given (pubkey,
     292             :    fork) pair, there is no concurrent acquire that holds a writable
     293             :    acc while another acquire for the same account on the same fork is
     294             :    outstanding (whether readable or writable).  Specifically:
     295             : 
     296             :      - Multiple concurrent read-only acquires of the same account on the
     297             :        same fork are permitted.
     298             :      - A writable acquire of an account on a given fork must not overlap
     299             :        with any other acquire (read or write) of that same account on
     300             :        that same fork.
     301             :      - Acquires of the same account on _different_ forks are always safe
     302             :        and may overlap freely, provided that all releases on an ancestor
     303             :        fork have completed before any acquire on a descendant fork
     304             :        begins.  In particular, a fork must finish all of its transaction
     305             :        execution (including committing or cancelling every writable
     306             :        account) before a child fork is attached and begins acquiring.
     307             :        This is naturally guaranteed by the replay scheduler, which does
     308             :        not activate a child block until the parent block is fully done.
     309             :        Concurrent acquires across unrelated sibling forks have no
     310             :        ordering requirement.
     311             :      - A read-only acquire on a frozen ancestor fork may begin after
     312             :        descendant-fork acquires (read or write) have already begun.  The
     313             :        executor relies on this: while a child bank executes (writably
     314             :        acquiring its own-fork accounts), it also read-only acquires the
     315             :        program's implicit programdata on the frozen parent fork.  This
     316             :        is safe because the parent is frozen, no writer ever commits to
     317             :        it so the read-only acquire cannot overlap any same-fork write,
     318             :        and read-only acquires never mutate acc pool or fork state.
     319             : 
     320             :    Violating this contract is undefined behavior and will likely crash
     321             :    with an assertion failure inside the cache refcount logic.  In
     322             :    practice, these constraints are naturally satisfied by the Solana
     323             :    execution model: each transaction has exclusive write locks on its
     324             :    writable accounts within a slot, the scheduler ensures no two
     325             :    concurrent transactions write to the same account on the same fork,
     326             :    and the replay scheduler serializes parent block completion before
     327             :    child block activation on the same fork chain.
     328             : 
     329             :    When a writable account is committed as an "overwrite" (same
     330             :    fork), the acc pool element's metadata fields (size, lamports,
     331             :    offset) are mutated in place, and the cache line's owner field is
     332             :    updated.  This is safe because these mutations
     333             :    only happen on the acc element whose generation matches the
     334             :    committing fork.  A concurrent acquire on a different fork cannot
     335             :    observe an in-place mutation of the same acc element for a child fork
     336             :    to even exist, the parent must be frozen and no longer undergoing
     337             :    modifications.  All acc pool fields are effectively immutable from
     338             :    the perspective of any concurrent cross-fork reader.
     339             : 
     340             :    out_accs is an array of pubkeys_cnt cache accs to be filled in
     341             :    with the acquired accounts.  The cache will fill the owner, lamports,
     342             :    data_len, and data fields of each acc if the acquire is successful,
     343             :    and the account exists.  If the account does not exist, the lamports
     344             :    field will be set to zero and other fields are undefined. */
     345             : 
     346             : void
     347             : fd_accdb_acquire( fd_accdb_t *          accdb,
     348             :                   fd_accdb_fork_id_t    fork_id,
     349             :                   ulong                 pubkeys_cnt,
     350             :                   uchar const * const * pubkeys,
     351             :                   int *                 writable,
     352             :                   fd_acc_t *            out_accs );
     353             : 
     354             : void
     355             : fd_accdb_acquire_a( fd_accdb_t *          accdb,
     356             :                     fd_accdb_fork_id_t    fork_id,
     357             :                     ulong                 pubkeys_cnt,
     358             :                     uchar const * const * pubkeys,
     359             :                     int *                 writable,
     360             :                     fd_acc_t *            out_accs );
     361             : 
     362             : void
     363             : fd_accdb_acquire_b( fd_accdb_t *          accdb,
     364             :                     fd_accdb_fork_id_t    fork_id,
     365             :                     ulong                 reserved_cnt,
     366             :                     ulong                 pubkeys_cnt,
     367             :                     uchar const * const * pubkeys,
     368             :                     int *                 writable,
     369             :                     fd_acc_t *            out_accs );
     370             : 
     371             : /* fd_accdb_release releases previously acquired accounts back to the
     372             :    cache, and if any of the released writable accounts have their commit
     373             :    bit set, the cache will write the changes back to the database.  The
     374             :    caller must guarantee that the accs being released were previously
     375             :    acquired and not yet released, and that the pubkeys in the accs
     376             :    match the pubkeys of the acquired accounts.  The accs need not be
     377             :    a specific set that was acquired together, although this is
     378             :    recommended.  The fork that each acc refers to must still exist
     379             :    (not yet purged or advanced past) at the time of release.  This
     380             :    includes forks that would be implicitly purged by a concurrent
     381             :    advance_root on a sibling — the caller must ensure advance_root
     382             :    is not called until all releases on affected forks have completed.
     383             :    Releasing accounts for a fork that has been purged or recycled is
     384             :    undefined behavior. */
     385             : 
     386             : void
     387             : fd_accdb_release( fd_accdb_t * accdb,
     388             :                   ulong        accs_cnt,
     389             :                   fd_acc_t *   accs );
     390             : 
     391             : void
     392             : fd_accdb_release_ab( fd_accdb_t * accdb,
     393             :                      ulong        accs_cnt,
     394             :                      fd_acc_t *   accs,
     395             :                      ulong        execs_cnt,
     396             :                      fd_acc_t *   execs );
     397             : 
     398             : fd_acc_t
     399             : fd_accdb_read_one( fd_accdb_t *       accdb,
     400             :                    fd_accdb_fork_id_t fork_id,
     401             :                    uchar const *      pubkey );
     402             : 
     403             : fd_acc_t
     404             : fd_accdb_write_one( fd_accdb_t *       accdb,
     405             :                     fd_accdb_fork_id_t fork_id,
     406             :                     uchar const *      pubkey );
     407             : 
     408             : void
     409             : fd_accdb_unwrite_one( fd_accdb_t * accdb,
     410             :                       fd_acc_t *   acc );
     411             : 
     412             : void
     413             : fd_accdb_unread_one( fd_accdb_t * accdb,
     414             :                      fd_acc_t *   acc );
     415             : 
     416             : int
     417             : fd_accdb_exists( fd_accdb_t *       accdb,
     418             :                  fd_accdb_fork_id_t fork_id,
     419             :                  uchar const *      pubkey );
     420             : 
     421             : /* fd_accdb_probe_pd_this_fork checks whether the newest version of
     422             :    pubkey visible on fork_id was committed on fork_id itself.  If so,
     423             :    returns 1 and sets *out_pd_write to that version's pd_write flag,
     424             :    *out_data_len to its data length, and *out_lamports to its lamport
     425             :    balance.  Otherwise returns 0, sets *out_pd_write to 0, and leaves
     426             :    *out_data_len and *out_lamports untouched.
     427             : 
     428             :    Reads only metadata, not account data.  out_pd_write deliberately
     429             :    ignores lamports: a programdata closed this slot is a lamports==0
     430             :    tombstone that must still report pd_write=1 so the loader's
     431             :    DelayVisibility gate fires.  out_lamports is reported separately so
     432             :    that callers doing account deadness checks have the current fork's
     433             :    deadness.
     434             : 
     435             :    Note that out_lamports and out_data_len are not read atomically.
     436             :    Caller is responsible for ensuring ordering if racing is not
     437             :    acceptable.
     438             : 
     439             :    Full join only. */
     440             : 
     441             : int
     442             : fd_accdb_probe_pd_this_fork( fd_accdb_t *       accdb,
     443             :                              fd_accdb_fork_id_t fork_id,
     444             :                              uchar const *      pubkey,
     445             :                              int *              out_pd_write,
     446             :                              ulong *            out_data_len,
     447             :                              ulong *            out_lamports );
     448             : 
     449             : /* fd_accdb_read_one_nocache reads one account at fork_id into
     450             :    caller-provided output buffers.  Suitable for processes that mmap the
     451             :    accdb data region read-only: it never mutates any cache line, index
     452             :    entry, or record.  The only write it makes into accdb shmem is
     453             :    publishing this joiner's epoch (to hold off compaction for the
     454             :    duration of the read), and that is done through a separately-mmap'd
     455             :    writable page aliasing the joiner's own epoch slot, not the read-only
     456             :    region.
     457             : 
     458             :    out_owner must point at a 32-byte buffer.  out_data must point at a
     459             :    buffer of at least FD_RUNTIME_ACC_SZ_MAX (10 MiB) bytes, the maximum
     460             :    account data size; the function does not bound-check against the
     461             :    account's actual length.  On a cache hit the bytes are memcpy'd from
     462             :    the cache slot using a try-read-test (ABA) loop; on a miss the owner
     463             :    and data are preadv2'd from the disk fd passed at join time, scattered
     464             :    into out_owner and out_data via iovec (looping on short reads).
     465             : 
     466             :    If the account does not exist, *out_lamports is set to zero and the
     467             :    other outputs are undefined; otherwise *out_lamports is non-zero and
     468             :    out_executable, out_owner, out_data, and out_data_len are all filled
     469             :    in.
     470             : 
     471             :    The function takes no reference; nothing needs to be released. */
     472             : 
     473             : void
     474             : fd_accdb_read_one_nocache( fd_accdb_t *       accdb,
     475             :                            fd_accdb_fork_id_t fork_id,
     476             :                            uchar const *      pubkey,
     477             :                            ulong *            out_lamports,
     478             :                            int *              out_executable,
     479             :                            uchar *            out_owner,
     480             :                            uchar *            out_data,
     481             :                            ulong *            out_data_len );
     482             : 
     483             : /* fd_accdb_lamports returns the lamports of the account at fork_id, or
     484             :    zero if the account does not exist. */
     485             : 
     486             : ulong
     487             : fd_accdb_lamports( fd_accdb_t *       accdb,
     488             :                    fd_accdb_fork_id_t fork_id,
     489             :                    uchar const *      pubkey );
     490             : 
     491             : /* fd_accdb_reset reinitializes the accdb to the state immediately after
     492             :    fd_accdb_new.  All in-memory index state is cleared and all pool
     493             :    joins are re-established.  The caller is responsible for truncating
     494             :    the on-disk file separately (e.g. via the snapwr tile).
     495             : 
     496             :    The caller must guarantee that no other thread is concurrently
     497             :    accessing the accdb (no outstanding acquires, no background work). */
     498             : 
     499             : void
     500             : fd_accdb_reset( fd_accdb_t * accdb );
     501             : 
     502             : /* fd_accdb_snapshot_write_one inserts or replaces an account during
     503             :    snapshot loading.  Returns -1 if the write was ignored (an existing
     504             :    acc has a higher slot), 1 if a new acc was inserted, 2 if an
     505             :    existing acc was replaced.  When 2 is returned, *out_replaced_lamports
     506             :    is set to the lamports of the replaced acc.  Otherwise it is set to
     507             :    0.  out_replaced_lamports must be non-NULL.
     508             : 
     509             :    slot must be <= UINT_MAX.  The slot is held in a 32-bit scratch field
     510             :    during snapshot loading; the accdb format must be widened before
     511             :    Solana reaches slot 2^32.  Passing a larger slot crashes the
     512             :    process.
     513             : 
     514             :    fork_id controls recovery behavior:
     515             : 
     516             :      USHORT_MAX, full-snapshot mode.  Existing entries with the same
     517             :                  pubkey are replaced in-place.  No txn entries are
     518             :                  created.
     519             : 
     520             :      other,      incremental-snapshot mode.  Cross-snapshot overrides
     521             :                  (existing entry from a different fork) insert a NEW
     522             :                  acc_pool entry alongside the old one and create a txn
     523             :                  record on fork_id, so fd_accdb_purge can revert the
     524             :                  incremental writes on failure.  Intra-fork duplicates
     525             :                  (same pubkey from the same fork) are still replaced
     526             :                  in-place. */
     527             : 
     528             : int
     529             : fd_accdb_snapshot_write_one( fd_accdb_t *       accdb,
     530             :                              fd_accdb_fork_id_t fork_id,
     531             :                              uchar const *      pubkey,
     532             :                              ulong              slot,
     533             :                              ulong              lamports,
     534             :                              ulong              data_len,
     535             :                              int                executable,
     536             :                              ulong *            out_replaced_lamports );
     537             : 
     538             : /* fd_accdb_snapshot_write_batch processes up to 8 accounts at once,
     539             :    using software prefetching to overlap hash chain memory latency with
     540             :    useful work.  This function is not thread safe and must not be called
     541             :    concurrently.  Each pubkey[i] points to a 32-byte public key.
     542             :    *out_replaced_lamports is set to the sum of the lamports of all
     543             :    accounts replaced by this batch (i.e. the previous lamports value of
     544             :    each account whose acc was overwritten).  *out_ignored_lamports is
     545             :    set to the sum of the lamports of all accounts ignored by this batch
     546             :    (i.e. the lamports of each input account whose write was dropped
     547             :    because an acc with a higher slot already exists).  Returns 0 on
     548             :    success, -1 if the batch contained two entries with the same pubkey
     549             :    (a corrupt-snapshot signal — the caller should flag the snapshot
     550             :    malformed).  Output counters are not meaningful when -1 is returned.
     551             : 
     552             :    Each slots[i] must be <= UINT_MAX (see fd_accdb_snapshot_write_one
     553             :    for the rationale).  Passing a larger slot crashes the process.
     554             : 
     555             :    fork_id has the same semantics as in fd_accdb_snapshot_write_one:
     556             :    USHORT_MAX for full-snapshot mode, otherwise incremental mode with
     557             :    txn tracking on the specified fork. */
     558             : 
     559             : int
     560             : fd_accdb_snapshot_write_batch( fd_accdb_t *        accdb,
     561             :                                fd_accdb_fork_id_t  fork_id,
     562             :                                ulong               cnt,
     563             :                                uchar const * const pubkeys[],
     564             :                                ulong  const        slots[],
     565             :                                ulong  const        lamports[],
     566             :                                ulong  const        data_lens[],
     567             :                                int    const        executables[],
     568             :                                ulong *             accounts_ignored,
     569             :                                ulong *             accounts_replaced,
     570             :                                ulong *             accounts_loaded,
     571             :                                ulong *             out_replaced_lamports,
     572             :                                ulong *             out_ignored_lamports );
     573             : 
     574             : /* fd_accdb_background performs one unit of background work.
     575             : 
     576             :    THREADING MODEL
     577             : 
     578             :    The accdb API is split across three thread roles:
     579             : 
     580             :      T1 (replay): calls attach_child, advance_root, purge, acquire, and
     581             :          release.  attach_child runs inline on T1. advance_root and
     582             :          purge submit a command into a shared- memory slot and return
     583             :          immediately; the heavy work is deferred to T2.
     584             : 
     585             :      T2 (accdb tile / background): calls fd_accdb_background repeatedly.
     586             :          This is the only function T2 should call.
     587             : 
     588             :      T3 (executor tiles, 1..N): call acquire and release.
     589             : 
     590             :    acquire and release may be called concurrently from T1 and any number
     591             :    of T3 threads.
     592             : 
     593             :    Read-only acquire/release on a fork F may run concurrently with
     594             :    advance_root(F) (rooting F itself).
     595             : 
     596             :    fd_accdb_background must be called from exactly one thread (T2). It
     597             :    must not be called concurrently with itself.
     598             : 
     599             :    BEHAVIOR
     600             : 
     601             :    First checks for a pending advance_root or purge command from T1; if
     602             :    one is present it executes the command, sets *charge_busy to 1, and
     603             :    returns immediately without doing compaction. Otherwise, attempts one
     604             :    step of compaction at each layer, setting *charge_busy if work was
     605             :    done. */
     606             : 
     607             : void
     608             : fd_accdb_background( fd_accdb_t * accdb,
     609             :                      int *        charge_busy );
     610             : 
     611             : /* fd_accdb_shmetrics returns a pointer to the shared metrics counters
     612             :    for the given accdb instance.  The returned pointer remains valid
     613             :    for the lifetime of the underlying shmem. */
     614             : 
     615             : fd_accdb_shmem_metrics_t const *
     616             : fd_accdb_shmetrics( fd_accdb_t * accdb );
     617             : 
     618             : /* fd_accdb_metrics returns a pointer to the per-thread metrics counters
     619             :    for the given accdb instance.  The returned pointer remains valid
     620             :    for the lifetime of the underlying shmem. */
     621             : 
     622             : fd_accdb_metrics_t const *
     623             : fd_accdb_metrics( fd_accdb_t * accdb );
     624             : 
     625             : /* fd_accdb_flush_metrics publishes this joiner's pending layer-0 write
     626             :    metrics.  Normal layer-0 writes defer these metrics by default.
     627             : 
     628             :    NOTE: A flush delayed past partition reuse can credit old counters
     629             :    to the new partition.  The impact on metrics accuracy is expected
     630             :    to be rare and small because partitions are rarely reused and
     631             :    metrics flush often. */
     632             : 
     633             : void
     634             : fd_accdb_flush_metrics( fd_accdb_t * accdb );
     635             : 
     636             : /* fd_accdb_cache_class_occupancy snapshots the current per-size-class
     637             :    cache occupancy and capacity into the caller-provided arrays, each
     638             :    of which must have FD_ACCDB_CACHE_CLASS_CNT entries.  used[c] is the
     639             :    number of slots in class c that currently hold a cache acc (i.e.
     640             :    slots that have been allocated lazily and are not sitting in the
     641             :    free list).  max[c] is the total slot capacity of class c.  Reads
     642             :    are done with relaxed (volatile) loads and may be momentarily
     643             :    inconsistent with each other under contention. */
     644             : 
     645             : void
     646             : fd_accdb_cache_class_occupancy( fd_accdb_t * accdb,
     647             :                                 ulong *      used,
     648             :                                 ulong *      max,
     649             :                                 ulong *      reserved );
     650             : 
     651             : /* fd_accdb_cache_class_thresholds returns the per-size-class preeviction
     652             :    thresholds, expressed as used-slot counts (so they're directly
     653             :    comparable to occupancy.used and occupancy.max).  Each output array
     654             :    must have FD_ACCDB_CACHE_CLASS_CNT entries.  target_used[c] is the
     655             :    used count the background preevict pass tries to drive towards (max -
     656             :    cache_free_target).  low_water_used[c] is the used count at which the
     657             :    preevict pass starts firing (max - cache_free_low_water).  Both are
     658             :    set once at init and are stable for the lifetime of the cache. */
     659             : 
     660             : void
     661             : fd_accdb_cache_class_thresholds( fd_accdb_t * accdb,
     662             :                                  ulong *      target_used,
     663             :                                  ulong *      low_water_used );
     664             : 
     665             : /* FD_ACCDB_METRICS_WRITE publishes the per-joiner accdb runtime metrics
     666             :    for tile prefix TILE.  TILE must be a tile that declares the
     667             :    AccdbAccountAcquired/... counters in metrics.xml (e.g. EXECLE,
     668             :    EXECRP, REPLAY, TOWER, ACCDB).  m must be a fd_accdb_metrics_t const *
     669             :    for the joiner whose counters should be published. */
     670             : 
     671           0 : #define FD_ACCDB_METRICS_WRITE( TILE, m ) do {                                              \
     672           0 :     fd_accdb_metrics_t const * _m = (m);                                                    \
     673           0 :     FD_MCNT_ENUM_COPY( TILE, ACCDB_ACCOUNT_ACQUIRED,          _m->accounts_acquired_per_class          ); \
     674           0 :     FD_MCNT_ENUM_COPY( TILE, ACCDB_ACCOUNT_WRITABLE_ACQUIRED, _m->writable_accounts_acquired_per_class ); \
     675           0 :     FD_MCNT_ENUM_COPY( TILE, ACCDB_ACCOUNT_EVICTED,        _m->accounts_evicted_per_class        ); \
     676           0 :     FD_MCNT_ENUM_COPY( TILE, ACCDB_ACCOUNT_COMMITTED_NEW,       _m->accounts_committed_new_per_class       ); \
     677           0 :     FD_MCNT_ENUM_COPY( TILE, ACCDB_ACCOUNT_COMMITTED_OVERWRITE, _m->accounts_committed_overwrite_per_class ); \
     678           0 :     FD_MCNT_ENUM_COPY( TILE, ACCDB_ACCOUNT_NOT_FOUND,   _m->accounts_not_found_per_class ); \
     679           0 :     FD_MCNT_SET( TILE, ACCDB_ACCOUNT_WAITED,             _m->accounts_waited            ); \
     680           0 :     FD_MCNT_SET( TILE, ACCDB_BATCH_ACQUIRED,             _m->acquire_calls              ); \
     681           0 :     FD_MCNT_SET( TILE, ACCDB_ACQUIRE_FAILED,             _m->acquire_failed             ); \
     682           0 :     FD_MCNT_SET( TILE, ACCDB_BYTES_READ,                 _m->bytes_read                 ); \
     683           0 :     FD_MCNT_SET( TILE, ACCDB_READ_OPERATION,             _m->read_ops                   ); \
     684           0 :     FD_MCNT_SET( TILE, ACCDB_BYTES_WRITTEN,              _m->bytes_written              ); \
     685           0 :     FD_MCNT_SET( TILE, ACCDB_WRITE_OPERATION,            _m->write_ops                  ); \
     686           0 :     FD_MCNT_SET( TILE, ACCDB_BYTES_COPIED,               _m->bytes_copied               ); \
     687           0 :   } while(0)
     688             : 
     689             : /* FD_ACCDB_METRICS_WRITE_RO is the read-only joiner subset of
     690             :    FD_ACCDB_METRICS_WRITE.  It only emits the counters that
     691             :    fd_accdb_read_one_nocache touches; tiles that join readonly
     692             :    (e.g. RPC) declare only this subset of counters in metrics.xml. */
     693             : 
     694           0 : #define FD_ACCDB_METRICS_WRITE_RO( TILE, m ) do {                                           \
     695           0 :     fd_accdb_metrics_t const * _m = (m);                                                    \
     696           0 :     FD_MCNT_ENUM_COPY( TILE, ACCDB_ACCOUNT_ACQUIRED,  _m->accounts_acquired_per_class  ); \
     697           0 :     FD_MCNT_ENUM_COPY( TILE, ACCDB_ACCOUNT_NOT_FOUND, _m->accounts_not_found_per_class ); \
     698           0 :     FD_MCNT_SET( TILE, ACCDB_ACCOUNT_WAITED,    _m->accounts_waited   ); \
     699           0 :     FD_MCNT_SET( TILE, ACCDB_BATCH_ACQUIRED,    _m->acquire_calls     ); \
     700           0 :     FD_MCNT_SET( TILE, ACCDB_BYTES_READ,        _m->bytes_read        ); \
     701           0 :     FD_MCNT_SET( TILE, ACCDB_READ_OPERATION,    _m->read_ops          ); \
     702           0 :     FD_MCNT_SET( TILE, ACCDB_BYTES_COPIED,      _m->bytes_copied      ); \
     703           0 :   } while(0)
     704             : 
     705             : FD_PROTOTYPES_END
     706             : 
     707             : #endif /* HEADER_fd_src_flamenco_accdb_fd_accdb_h */

Generated by: LCOV version 1.14