LCOV - code coverage report
Current view: top level - flamenco/progcache - fd_progcache_user.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 2 14 14.3 %
Date: 2026-03-19 18:19:27 Functions: 0 92 0.0 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_progcache_fd_progcache_user_h
       2             : #define HEADER_fd_src_flamenco_progcache_fd_progcache_user_h
       3             : 
       4             : /* fd_progcache_user.h provides an API for managing a cache of loaded
       5             :    Solana on-chain program.
       6             : 
       7             :    ### Background
       8             : 
       9             :    Solana on-chain programs are rarely updated but frequently executed.
      10             :    Before a program can be executed, it must be loaded and verified,
      11             :    which is costly.
      12             : 
      13             :    ### Fork management
      14             : 
      15             :    The program cache is fork-aware (using funk transactions).  Txn-level
      16             :    operations take an exclusive lock over the cache (record ops are
      17             :    stalled indefinitely until the txn completes).
      18             : 
      19             :    ### Cache entry
      20             : 
      21             :    Each Solana program can have a number of program cache entries
      22             :    (typically only zero or one, in rare cases where the program content
      23             :    differs across forks multiple).
      24             : 
      25             :    A cache entry consists of a funk_rec object (from a preallocated
      26             :    object pool), and a variable-sized fd_progcache_entry struct
      27             :    (from an fd_alloc heap).
      28             : 
      29             :    ### Cache fill policy
      30             : 
      31             :    fd_progcache is lazily filled on reads, and eagerly invalidated
      32             :    if underlying programs are written to.
      33             : 
      34             :    ### Cache evict policy
      35             : 
      36             :    Cache eviction (i.e. force removal of potentially useful records)
      37             :    happens on fill.  Specifically, cache eviction is triggered when a
      38             :    cache fill fails to allocate from the wksp (fd_alloc) heap.
      39             : 
      40             :    fd_progcache further has a concept of "generations" (gen).  Each
      41             :    cache fill operation specifies a 'gen' number.  Only entries with a
      42             :    lower 'gen' number may get evicted.
      43             : 
      44             :    ### Garbage collect policy
      45             : 
      46             :    fd_progcache cleans up unused entries eagerly when:
      47             : 
      48             :    1. a database fork is cancelled (e.g. slot is rooted and competing
      49             :       history dies, or consensus layer prunes a fork)
      50             :    2. a cache entry is orphaned (updated or invalidated by an epoch
      51             :       boundary) */
      52             : 
      53             : #include "fd_progcache.h"
      54             : #include "fd_prog_load.h"
      55             : #include "../accdb/fd_accdb_base.h"
      56             : #include "../runtime/fd_runtime_const.h"
      57             : 
      58             : #define FD_PROGCACHE_DEPTH_MAX (8192UL)
      59             : 
      60             : struct fd_progcache_metrics {
      61             :   ulong lookup_cnt;
      62             :   ulong hit_cnt;
      63             :   ulong miss_cnt;
      64             :   ulong invalidate_cnt;
      65             :   ulong oom_heap_cnt;
      66             :   ulong oom_desc_cnt;
      67             :   ulong fill_cnt;
      68             :   ulong fill_tot_sz;
      69             :   ulong spill_cnt;
      70             :   ulong spill_tot_sz;
      71             :   ulong evict_cnt;
      72             :   ulong evict_tot_sz;
      73             :   ulong evict_freed_sz;
      74             :   ulong cum_pull_ticks;
      75             :   ulong cum_load_ticks;
      76             : };
      77             : 
      78             : typedef struct fd_progcache_metrics fd_progcache_metrics_t;
      79             : 
      80             : /* fd_progcache_t is a thread-local client to a program cache funk
      81             :    instance.  This struct is quite large and therefore not local/stack
      82             :    declaration-friendly. */
      83             : 
      84             : struct fd_progcache {
      85             :   fd_progcache_join_t join[1];
      86             :   fd_accdb_lineage_t  lineage[1];
      87             : 
      88             :   fd_progcache_metrics_t * metrics;
      89             : 
      90             :   uchar * scratch;
      91             :   ulong   scratch_sz;
      92             : 
      93             :   uint spill_active;
      94             : };
      95             : 
      96             : typedef struct fd_progcache fd_progcache_t;
      97             : 
      98             : FD_PROTOTYPES_BEGIN
      99             : 
     100             : extern FD_TL fd_progcache_metrics_t fd_progcache_metrics_default;
     101             : 
     102             : /* Constructor */
     103             : 
     104             : static inline ulong
     105           0 : fd_progcache_align( void ) {
     106           0 :   return alignof(fd_progcache_t);
     107           0 : }
     108             : 
     109             : static inline ulong
     110           0 : fd_progcache_footprint( void ) {
     111           0 :   return sizeof(fd_progcache_t);
     112           0 : }
     113             : 
     114             : static inline fd_progcache_t *
     115           0 : fd_progcache_new( void * ljoin ) {
     116           0 :   return ljoin;
     117           0 : }
     118             : 
     119             : static inline void *
     120           0 : fd_progcache_delete( void * ljoin ) {
     121           0 :   return ljoin;
     122           0 : }
     123             : 
     124             : /* fd_progcache_join joins the caller to a program cache shmem instance.
     125             :    scratch points to a FD_PROGCACHE_SCRATCH_ALIGN aligned scratch buffer
     126             :    and scratch_sz is the size of the largest program/ELF binary that is
     127             :    going to be loaded (typically max account data sz). */
     128             : 
     129             : fd_progcache_t *
     130             : fd_progcache_join( fd_progcache_t *       ljoin,
     131             :                    fd_progcache_shmem_t * shmem,
     132             :                    uchar *                scratch,
     133             :                    ulong                  scratch_sz );
     134             : 
     135          12 : #define FD_PROGCACHE_SCRATCH_ALIGN     (64UL)
     136          12 : #define FD_PROGCACHE_SCRATCH_FOOTPRINT FD_RUNTIME_ACC_SZ_MAX
     137             : 
     138             : /* fd_progcache_leave detaches the caller from a program cache. */
     139             : 
     140             : void *
     141             : fd_progcache_leave( fd_progcache_t *        cache,
     142             :                     fd_progcache_shmem_t ** opt_shmem );
     143             : 
     144             : /* Record-level operations ********************************************/
     145             : 
     146             : /* fd_progcache_peek queries the program cache for an existing cache
     147             :    entry.  Does not fill the cache.  Returns a pointer to the entry on
     148             :    cache hit.  Returns NULL on cache miss.  It is the caller's
     149             :    responsibility to release the returned record with
     150             :    fd_progcache_rec_close. */
     151             : 
     152             : fd_progcache_rec_t * /* read locked */
     153             : fd_progcache_peek( fd_progcache_t *          cache,
     154             :                    fd_funk_txn_xid_t const * xid,
     155             :                    void const *              prog_addr,
     156             :                    ulong                     epoch_slot0 );
     157             : 
     158             : /* fd_progcache_pull loads a program from cache, filling the cache if
     159             :    necessary.  The load operation can have a number of outcomes:
     160             :    - Returns a pointer to an existing cache entry (cache hit, state
     161             :      either "Loaded" or "FailedVerification")
     162             :    - Returns a pointer to a newly created cache entry (cache fill,
     163             :      state either "Loaded" or "FailedVerification")
     164             :    - Returns NULL if the requested program account is not deployed (i.e.
     165             :      account is missing, the program is under visibility delay, or user
     166             :      has not finished uploading the program)
     167             :    In other words, this method guarantees to return a cache entry if a
     168             :    deployed program was found in the account database, and the program
     169             :    either loaded successfully, or failed ELF/bytecode verification.
     170             :    It is the caller's responsibility to release the returned record with
     171             :    fd_progcache_rec_close. */
     172             : 
     173             : fd_progcache_rec_t * /* read locked */
     174             : fd_progcache_pull( fd_progcache_t *           cache,
     175             :                    fd_accdb_user_t *          accdb,
     176             :                    fd_funk_txn_xid_t const *  xid,
     177             :                    void const *               prog_addr,
     178             :                    fd_prog_load_env_t const * env );
     179             : 
     180             : /* fd_progcache_invalidate marks the program at the given address as
     181             :    invalidated (typically due to a change of program content).  This
     182             :    creates a non-executable cache entry at the given xid.
     183             : 
     184             :    After a program has been invalidated at xid, it is forbidden to pull
     185             :    the same entry at the same xid.  (Invalidations should happen after
     186             :    replaying transactions).
     187             : 
     188             :    Assumes that xid is a valid fork graph node (not rooted) until
     189             :    invalidate returns. */
     190             : 
     191             : void
     192             : fd_progcache_invalidate( fd_progcache_t *          cache,
     193             :                          fd_funk_txn_xid_t const * xid,
     194             :                          void const *              prog_addr,
     195             :                          ulong                     slot );
     196             : 
     197             : /* fd_progcache_rec_close releases a cache record handle returned by
     198             :    fd_progcache_{pull,peek}. */
     199             : 
     200             : void
     201             : fd_progcache_rec_close( fd_progcache_t *     cache,
     202             :                         fd_progcache_rec_t * rec );
     203             : 
     204             : FD_PROTOTYPES_END
     205             : 
     206             : #endif /* HEADER_fd_src_flamenco_fd_progcache_h */

Generated by: LCOV version 1.14