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

Generated by: LCOV version 1.14