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

Generated by: LCOV version 1.14