LCOV - code coverage report
Current view: top level - flamenco/progcache - fd_progcache_user.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 1 15 6.7 %
Date: 2025-12-06 04:45:29 Functions: 0 72 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_rec.h"
      54             : #include "fd_prog_load.h"
      55             : #include "../accdb/fd_accdb_base.h"
      56             : #include "../runtime/fd_runtime_const.h"
      57             : #include "../../funk/fd_funk.h"
      58             : 
      59         264 : #define FD_PROGCACHE_DEPTH_MAX (128UL)
      60             : 
      61             : struct fd_progcache_metrics {
      62             :   ulong fork_switch_cnt;
      63             :   ulong miss_cnt;
      64             :   ulong hit_cnt;
      65             :   ulong hit_tot_sz;
      66             :   ulong fill_cnt;
      67             :   ulong fill_tot_sz;
      68             :   ulong fill_fail_cnt;
      69             :   ulong dup_insert_cnt;
      70             :   ulong invalidate_cnt;
      71             : };
      72             : 
      73             : typedef struct fd_progcache_metrics fd_progcache_metrics_t;
      74             : 
      75             : /* fd_progcache_t is a thread-local client to a program cache funk
      76             :    instance.  This struct is quite large and therefore not local/stack
      77             :    declaration-friendly. */
      78             : 
      79             : struct fd_progcache {
      80             :   fd_funk_t funk[1];
      81             : 
      82             :   /* Current fork cache */
      83             :   fd_funk_txn_xid_t fork[ FD_PROGCACHE_DEPTH_MAX ];
      84             :   ulong             fork_depth;
      85             : 
      86             :   fd_progcache_metrics_t * metrics;
      87             : 
      88             :   uchar * scratch;
      89             :   ulong   scratch_sz;
      90             : };
      91             : 
      92             : typedef struct fd_progcache fd_progcache_t;
      93             : 
      94             : FD_PROTOTYPES_BEGIN
      95             : 
      96             : extern FD_TL fd_progcache_metrics_t fd_progcache_metrics_default;
      97             : 
      98             : /* Constructor */
      99             : 
     100             : static inline ulong
     101           0 : fd_progcache_align( void ) {
     102           0 :   return alignof(fd_progcache_t);
     103           0 : }
     104             : 
     105             : static inline ulong
     106           0 : fd_progcache_footprint( void ) {
     107           0 :   return sizeof(fd_progcache_t);
     108           0 : }
     109             : 
     110             : static inline fd_progcache_t *
     111           0 : fd_progcache_new( void * ljoin ) {
     112           0 :   return ljoin;
     113           0 : }
     114             : 
     115             : static inline void *
     116           0 : fd_progcache_delete( void * ljoin ) {
     117           0 :   return ljoin;
     118           0 : }
     119             : 
     120             : /* fd_progcache_join joins the caller to a program cache funk instance.
     121             :    scratch points to a FD_PROGCACHE_SCRATCH_ALIGN aligned scratch buffer
     122             :    and scratch_sz is the size of the largest program/ELF binary that is
     123             :    going to be loaded (typically max account data sz). */
     124             : 
     125             : fd_progcache_t *
     126             : fd_progcache_join( fd_progcache_t * ljoin,
     127             :                    void *           shfunk,
     128             :                    uchar *          scratch,
     129             :                    ulong            scratch_sz );
     130             : 
     131           0 : #define FD_PROGCACHE_SCRATCH_ALIGN     (64UL)
     132           0 : #define FD_PROGCACHE_SCRATCH_FOOTPRINT FD_RUNTIME_ACC_SZ_MAX
     133             : 
     134             : /* fd_progcache_leave detaches the caller from a program cache. */
     135             : 
     136             : void *
     137             : fd_progcache_leave( fd_progcache_t * cache,
     138             :                     void **          opt_shfunk );
     139             : 
     140             : /* Record-level operations ********************************************/
     141             : 
     142             : /* fd_progcache_peek queries the program cache for an existing cache
     143             :    entry.  Does not fill the cache.  Returns a pointer to the entry on
     144             :    cache hit (invalidated by the next non-const API call).  Returns NULL
     145             :    on cache miss. */
     146             : 
     147             : fd_progcache_rec_t const *
     148             : fd_progcache_peek( fd_progcache_t *          cache,
     149             :                    fd_funk_txn_xid_t const * xid,
     150             :                    void const *              prog_addr,
     151             :                    ulong                     epoch_slot0 );
     152             : 
     153             : /* fd_progcache_pull loads a program from cache, filling the cache if
     154             :    necessary.  The load operation can have a number of outcomes:
     155             :    - Returns a pointer to an existing cache entry (cache hit, state
     156             :      either "Loaded" or "FailedVerification")
     157             :    - Returns a pointer to a newly created cache entry (cache fill,
     158             :      state either "Loaded" or "FailedVerification")
     159             :    - Returns NULL if the requested program account is not deployed (i.e.
     160             :      account is missing, the program is under visibility delay, or user
     161             :      has not finished uploading the program)
     162             :    In other words, this method guarantees to return a cache entry if a
     163             :    deployed program was found in the account database, and the program
     164             :    either loaded successfully, or failed ELF/bytecode verification.
     165             :    Or it returns  */
     166             : 
     167             : fd_progcache_rec_t const *
     168             : fd_progcache_pull( fd_progcache_t *           cache,
     169             :                    fd_accdb_user_t *          accdb,
     170             :                    fd_funk_txn_xid_t const *  xid,
     171             :                    void const *               prog_addr,
     172             :                    fd_prog_load_env_t const * env );
     173             : 
     174             : /* fd_progcache_invalidate marks the program at the given address as
     175             :    invalidated (typically due to a change of program content).  This
     176             :    creates a non-executable cache entry at the given xid.
     177             : 
     178             :    After a program has been invalidated at xid, it is forbidden to pull
     179             :    the same entry at the same xid.  (Invalidations should happen after
     180             :    replaying transactions). */
     181             : 
     182             : fd_progcache_rec_t const *
     183             : fd_progcache_invalidate( fd_progcache_t *          cache,
     184             :                          fd_funk_txn_xid_t const * xid,
     185             :                          void const *              prog_addr,
     186             :                          ulong                     slot );
     187             : 
     188             : FD_PROTOTYPES_END
     189             : 
     190             : #endif /* HEADER_fd_src_flamenco_fd_progcache_h */

Generated by: LCOV version 1.14