LCOV - code coverage report
Current view: top level - funk - fd_funk_rec.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 23 31 74.2 %
Date: 2026-01-23 05:02:40 Functions: 12 495 2.4 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_funk_fd_funk_rec_h
       2             : #define HEADER_fd_src_funk_fd_funk_rec_h
       3             : 
       4             : /* fd_funk_rec.h provides APIs for managing funk records */
       5             : 
       6             : #include "fd_funk_txn.h" /* Includes fd_funk_base.h */
       7             : 
       8             : /* FD_FUNK_REC_{ALIGN,FOOTPRINT} describe the alignment and footprint of
       9             :    a fd_funk_rec_t.  ALIGN will be a power of 2, footprint will be a
      10             :    multiple of align.  These are provided to facilitate compile time
      11             :    declarations. */
      12             : 
      13           0 : #define FD_FUNK_REC_ALIGN     (32UL)
      14             : 
      15             : /* FD_FUNK_REC_IDX_NULL gives the map record idx value used to represent
      16             :    NULL.  This value also set a limit on how large rec_max can be. */
      17             : 
      18    13592697 : #define FD_FUNK_REC_IDX_NULL (UINT_MAX)
      19             : 
      20             : /* A fd_funk_rec_t describes a funk record. */
      21             : 
      22             : struct __attribute__((aligned(FD_FUNK_REC_ALIGN))) fd_funk_rec {
      23             : 
      24             :   /* These fields are managed by the funk's rec_map */
      25             : 
      26             :   fd_funk_xid_key_pair_t pair;     /* Transaction id and record key pair */
      27             :   uint                   map_next; /* Internal use by map */
      28             : 
      29             :   /* These fields are managed by the user */
      30             : 
      31             :   uchar user[ 4 ];
      32             : 
      33             :   /* These fields are managed by funk */
      34             : 
      35             :   ulong ver_lock;  /* Record version and lock bits */
      36             : 
      37             :   uint  next_idx;  /* Record map index of next record in its transaction */
      38             :   uint  prev_idx;  /* Record map index of previous record in its transaction */
      39             : 
      40             :   /* Note: use of uint here requires FD_FUNK_REC_VAL_MAX to be at most
      41             :      (1UL<<28)-1. */
      42             : 
      43             :   ulong val_sz  : 28;  /* Num bytes in record value, in [0,val_max] */
      44             :   ulong val_max : 28;  /* Max byte  in record value, in [0,FD_FUNK_REC_VAL_MAX], 0 if val_gaddr is 0 */
      45             :   ulong tag     :  1;  /* Used for internal validation */
      46             :   ulong val_gaddr; /* Wksp gaddr on record value if any, 0 if val_max is 0
      47             :                       If non-zero, the region [val_gaddr,val_gaddr+val_max) will be a current fd_alloc allocation (such that it is
      48             :                       has tag wksp_tag) and the owner of the region will be the record. The allocator is
      49             :                       fd_funk_alloc(). IMPORTANT! HAS NO GUARANTEED ALIGNMENT! */
      50             : 
      51             : };
      52             : 
      53             : typedef struct fd_funk_rec fd_funk_rec_t;
      54             : 
      55             : FD_STATIC_ASSERT( sizeof(fd_funk_rec_t) == 3U*FD_FUNK_REC_ALIGN, record size is wrong );
      56             : 
      57             : #define FD_FUNK_REC_PAIR_FMT "xid=%lu:%lu,key=%016lx:%016lx:%016lx:%016lx"
      58             : #define FD_FUNK_REC_PAIR_FMT_ARGS(p) \
      59             :   (p).xid->ul[0], (p).xid->ul[1], \
      60             :   fd_ulong_bswap( (p).key->ul[0] ), fd_ulong_bswap( (p).key->ul[1] ), \
      61             :   fd_ulong_bswap( (p).key->ul[2] ), fd_ulong_bswap( (p).key->ul[3] )
      62             : 
      63             : /* fd_funk_rec_map allows for indexing records by their (xid,key) pair.
      64             :    It is used to store all records of the last published transaction and
      65             :    the records being updated for a transaction that is in-preparation.
      66             :    Published records are stored under the pair (root,key).  (This is
      67             :    done so that publishing a transaction doesn't require updating all
      68             :    transaction id of all the records that were not updated by the
      69             :    publish.) */
      70             : 
      71             : #define POOL_NAME       fd_funk_rec_pool
      72             : #define POOL_ELE_T      fd_funk_rec_t
      73             : #define POOL_IDX_T      uint
      74             : #define POOL_NEXT       map_next
      75             : #define POOL_IMPL_STYLE 1
      76             : #define POOL_LAZY       1
      77             : #include "../util/tmpl/fd_pool_para.c"
      78             : 
      79             : #define MAP_NAME              fd_funk_rec_map
      80       48990 : #define MAP_ELE_T             fd_funk_rec_t
      81             : #define MAP_KEY_T             fd_funk_xid_key_pair_t
      82             : #define MAP_KEY               pair
      83     2042934 : #define MAP_KEY_EQ(k0,k1)     fd_funk_xid_key_pair_eq((k0),(k1))
      84     2693127 : #define MAP_KEY_HASH(k0,seed) fd_funk_xid_key_pair_hash((k0),(seed))
      85             : #define MAP_IDX_T             uint
      86       48990 : #define MAP_NEXT              map_next
      87             : #define MAP_MAGIC             (0xf173da2ce77ecdb0UL) /* Firedancer rec db version 0 */
      88    17951097 : #define FD_FUNK_REC_MAP_CNT_WIDTH 43
      89    12734385 : #define MAP_CNT_WIDTH         FD_FUNK_REC_MAP_CNT_WIDTH
      90             : #define MAP_IMPL_STYLE        1
      91             : #define MAP_PEDANTIC          1
      92             : #include "../util/tmpl/fd_map_chain_para.c"
      93             : 
      94             : typedef fd_funk_rec_map_query_t fd_funk_rec_query_t;
      95             : 
      96             : /* fd_funk_rec_prepare_t represents a new record that has been
      97             :    prepared but not inserted into the map yet. See documentation for
      98             :    fd_funk_rec_prepare. */
      99             : 
     100             : struct _fd_funk_rec_prepare {
     101             :   fd_funk_rec_t * rec;
     102             :   uint *          rec_head_idx;
     103             :   uint *          rec_tail_idx;
     104             : };
     105             : 
     106             : typedef struct _fd_funk_rec_prepare fd_funk_rec_prepare_t;
     107             : 
     108             : FD_PROTOTYPES_BEGIN
     109             : 
     110             : /* fd_funk_rec_idx_is_null returns 1 if idx is FD_FUNK_REC_IDX_NULL and
     111             :    0 otherwise. */
     112             : 
     113     3154290 : FD_FN_CONST static inline int fd_funk_rec_idx_is_null( uint idx ) { return idx==FD_FUNK_REC_IDX_NULL; }
     114             : 
     115             : /* Accessors */
     116             : 
     117             : /* FIXME deprecate */
     118             : 
     119             : fd_funk_rec_t *
     120             : fd_funk_rec_query_try( fd_funk_t *               funk,
     121             :                        fd_funk_txn_xid_t const * xid,
     122             :                        fd_funk_rec_key_t const * key,
     123             :                        fd_funk_rec_query_t *     query );
     124             : 
     125             : /* fd_funk_rec_{pair,xid,key} returns a pointer in the local address
     126             :    space of the {(transaction id,record key) pair,transaction id,record
     127             :    key} of a live record.  Assumes rec points to a live record in the
     128             :    caller's address space.  The lifetime of the returned pointer is the
     129             :    same as rec.  The value at the pointer will be constant for its
     130             :    lifetime. */
     131             : 
     132         231 : FD_FN_CONST static inline fd_funk_xid_key_pair_t const * fd_funk_rec_pair( fd_funk_rec_t const * rec ) { return &rec->pair;    }
     133       12237 : FD_FN_CONST static inline fd_funk_txn_xid_t const *      fd_funk_rec_xid ( fd_funk_rec_t const * rec ) { return rec->pair.xid; }
     134           0 : FD_FN_CONST static inline fd_funk_rec_key_t const *      fd_funk_rec_key ( fd_funk_rec_t const * rec ) { return rec->pair.key; }
     135             : 
     136             : /* fd_funk_rec_prepare creates an unpublished funk record entry.  This
     137             :    is the first step to adding a funk record to a transaction.  Record
     138             :    entry acquisition may fail if the record object pool is exhausted
     139             :    (FD_FUNK_ERR_REC) or the transaction is not writable
     140             :    (FD_FUNK_ERR_FROZEN).  The returned record entry (located in funk
     141             :    shared memory) is then either be cancelled or published by the
     142             :    caller.  This record is invisible to funk query or record-iteration
     143             :    operations until published.  Concurrent record preparation is fine. */
     144             : 
     145             : fd_funk_rec_t *
     146             : fd_funk_rec_prepare( fd_funk_t *               funk,
     147             :                      fd_funk_txn_xid_t const * xid,
     148             :                      fd_funk_rec_key_t const * key,
     149             :                      fd_funk_rec_prepare_t *   prepare,
     150             :                      int *                     opt_err );
     151             : 
     152             : /* fd_funk_rec_publish makes a prepared record globally visible.  First,
     153             :    registers a record with the txn's record list, then inserts it into
     154             :    the record map.  Concurrent record publishing is fine, even to the
     155             :    same transaction.  Crashes the application with FD_LOG_CRIT if the
     156             :    caller attempts to publish the same (txn,xid) key twice. */
     157             : 
     158             : void
     159             : fd_funk_rec_publish( fd_funk_t *             funk,
     160             :                      fd_funk_rec_prepare_t * prepare );
     161             : 
     162             : /* Misc */
     163             : 
     164             : /* fd_funk_rec_verify verifies the record map.  Returns FD_FUNK_SUCCESS
     165             :    if the record map appears intact and FD_FUNK_ERR_INVAL if not (logs
     166             :    details).  Meant to be called as part of fd_funk_verify.  As such, it
     167             :    assumes funk is non-NULL, fd_funk_{wksp,txn_map,rec_map} have been
     168             :    verified to work and the txn_map has been verified. */
     169             : 
     170             : int
     171             : fd_funk_rec_verify( fd_funk_t * funk );
     172             : 
     173             : /* Record locking ******************************************************
     174             : 
     175             :    The funk_rec 'ver_lock' field synchronizes record accesses via atomic
     176             :    CAS.  There exist three access types:
     177             :    - 'read':  read-only record access
     178             :    - 'write': record creation or modification
     179             :    - 'admin': record destruction (during rooting)
     180             : 
     181             :    Record locking has two goals:
     182             :    - Delay destruction of records until other accesses complete
     183             :    - Detect usage bugs (e.g. conflicting write attempts to the same
     184             :      record)
     185             : 
     186             :    'ver_lock' is encoded as two integers packed into a 64-bit ulong:
     187             :    - 'ver':  version counter incremented on every record destruction
     188             :              and creation (lsb=0 implies record is dead, lsb=1 implies
     189             :              record is alive)
     190             :    - 'lock': max implies record is write locked.  Otherwise, equals
     191             :              the number of active read locks.
     192             : 
     193             :    There further exist the following transitions:
     194             :    - 'write lock acquire': lock=0   --> lock=max
     195             :    - 'write lock release': lock=max --> lock=0
     196             :    - 'read lock acquire':  lock=n   --> lock=n+1
     197             :    - 'read lock release':  lock=n+1 --> lock=n
     198             :    - 'destroy':            ver=n    --> ver=n+1  (where n%2 == 0)
     199             :    - 'create':             ver=n    --> ver=n+1  (where n%2 == 1)
     200             : 
     201             : ***********************************************************************/
     202             : 
     203     2052321 : #define FD_FUNK_REC_LOCK_BIT_CNT (11)
     204         285 : #define FD_FUNK_REC_LOCK_MASK    ( (1UL<<FD_FUNK_REC_LOCK_BIT_CNT)-1UL )
     205      684012 : #define FD_FUNK_REC_VER_BIT_CNT  (64 - FD_FUNK_REC_LOCK_BIT_CNT)
     206      684012 : #define FD_FUNK_REC_VER_MASK     ( (1UL<<FD_FUNK_REC_VER_BIT_CNT)-1UL )
     207             : 
     208             : FD_FN_CONST static inline ulong
     209             : fd_funk_rec_ver_lock( ulong ver,
     210      684012 :                       ulong lock ) {
     211      684012 :   return ver<<FD_FUNK_REC_LOCK_BIT_CNT | lock;
     212      684012 : }
     213             : 
     214             : FD_FN_CONST static inline ulong
     215      684012 : fd_funk_rec_ver_bits( ulong ver_lock ) {
     216      684012 :   return ver_lock >> FD_FUNK_REC_LOCK_BIT_CNT;
     217      684012 : }
     218             : 
     219             : FD_FN_CONST static inline ulong
     220      684012 : fd_funk_rec_ver_inc( ulong ver ) {
     221      684012 :   return (ver+1UL) & FD_FUNK_REC_VER_MASK;
     222      684012 : }
     223             : 
     224             : FD_FN_CONST static inline ulong
     225           0 : fd_funk_rec_lock_bits( ulong ver_lock ) {
     226           0 :   return ver_lock & ( (1UL<<FD_FUNK_REC_LOCK_BIT_CNT)-1UL );
     227           0 : }
     228             : 
     229             : FD_FN_CONST static inline int
     230           0 : fd_funk_rec_ver_alive( ulong ver ) {
     231           0 :   return !!( ver & 1UL );
     232           0 : }
     233             : 
     234             : FD_PROTOTYPES_END
     235             : 
     236             : #endif /* HEADER_fd_src_funk_fd_funk_rec_h */

Generated by: LCOV version 1.14