LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_txncache_shmem.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 102 119 85.7 %
Date: 2026-07-11 05:27:41 Functions: 6 6 100.0 %

          Line data    Source code
       1             : #include "fd_txncache_shmem.h"
       2             : #include "fd_txncache_private.h"
       3             : 
       4             : #define POOL_NAME       blockcache_pool
       5         162 : #define POOL_T          fd_txncache_blockcache_shmem_t
       6             : #define POOL_IDX_T      ulong
       7      614370 : #define POOL_NEXT       pool.next
       8             : #define POOL_IMPL_STYLE 2
       9             : #include "../../util/tmpl/fd_pool.c"
      10             : 
      11             : #define MAP_NAME               blockhash_map
      12        3717 : #define MAP_KEY                blockhash
      13           0 : #define MAP_ELE_T              fd_txncache_blockcache_shmem_t
      14             : #define MAP_KEY_T              fd_hash_t
      15        3717 : #define MAP_PREV               blockhash_map.prev
      16        3717 : #define MAP_NEXT               blockhash_map.next
      17             : #define MAP_KEY_EQ(k0,k1)      fd_hash_eq( k0, k1 )
      18             : #define MAP_KEY_HASH(key,seed) (__extension__({ (void)(seed); fd_ulong_load_8_fast( (key)->uc ); }))
      19             : #define MAP_OPTIMIZE_RANDOM_ACCESS_REMOVAL 1
      20             : #define MAP_MULTI              1
      21             : #define MAP_IMPL_STYLE         2
      22             : #include "../../util/tmpl/fd_map_chain.c"
      23             : 
      24             : #define SLIST_NAME       root_slist
      25             : #define SLIST_ELE_T      fd_txncache_blockcache_shmem_t
      26             : #define SLIST_IDX_T      ulong
      27           0 : #define SLIST_NEXT       slist.next
      28             : #define SLIST_IMPL_STYLE 2
      29             : #include "../../util/tmpl/fd_slist.c"
      30             : 
      31             : FD_FN_CONST ushort
      32             : fd_txncache_max_txnpages_per_blockhash( ulong max_active_slots,
      33         216 :                                         ulong max_txn_per_slot ) {
      34             :   /* The maximum number of transaction pages we might need to store all
      35             :      the transactions that could be seen in a blockhash.
      36             : 
      37             :      In the worst case, every transaction in every live bank refers to
      38             :      the same blockhash. */
      39             : 
      40         216 :   ulong result = 1UL+(max_txn_per_slot*max_active_slots)/FD_TXNCACHE_TXNS_PER_PAGE;
      41         216 :   if( FD_UNLIKELY( result>USHORT_MAX-2UL ) ) return 0; /* MAX is the invalid flag, MAX-1 is the xbusy flag. */
      42         216 :   return (ushort)result;
      43         216 : }
      44             : 
      45             : FD_FN_CONST ushort
      46             : fd_txncache_max_txnpages( ulong max_active_slots,
      47         216 :                           ulong max_txn_per_slot ) {
      48             :   /* We need to be able to store potentially every slot that is live
      49             :      being completely full of transactions.  This would be
      50             : 
      51             :        max_active_slots*max_txn_per_slot
      52             : 
      53             :      transactions, except that we are counting pages here, not
      54             :      transactions.  It's not enough to divide by the page size, because
      55             :      pages might be wasted.  The maximum page wastage occurs when all
      56             :      the blockhashes except one have one transaction in them, and the
      57             :      remaining blockhash has all other transactions.  In that case, the
      58             :      full blockhash needs
      59             : 
      60             :        (max_active_slots*max_txn_per_slot)/FD_TXNCACHE_TXNS_PER_PAGE
      61             : 
      62             :      pages, and the other blockhashes need 1 page each. */
      63             : 
      64         216 :   ulong result = max_active_slots-1UL+max_active_slots*(1UL+(max_txn_per_slot-1UL)/FD_TXNCACHE_TXNS_PER_PAGE);
      65         216 :   if( FD_UNLIKELY( result>USHORT_MAX-2UL ) ) return 0; /* MAX is the invalid flag, MAX-1 is the xbusy flag. */
      66         216 :   return (ushort)result;
      67         216 : }
      68             : 
      69             : FD_FN_CONST ulong
      70         216 : fd_txncache_shmem_align( void ) {
      71         216 :   return FD_TXNCACHE_SHMEM_ALIGN;
      72         216 : }
      73             : 
      74             : FD_FN_CONST ulong
      75             : fd_txncache_shmem_footprint( ulong max_live_slots,
      76         108 :                              ulong max_txn_per_slot ) {
      77         108 :   if( FD_UNLIKELY( max_live_slots<1UL ) ) return 0UL;
      78         108 :   if( FD_UNLIKELY( max_txn_per_slot<1UL ) ) return 0UL;
      79             : 
      80         108 :   ulong max_active_slots = FD_TXNCACHE_MAX_BLOCKHASH_DISTANCE+max_live_slots;
      81         108 :   ulong blockhash_map_chains = fd_ulong_pow2_up( 2UL*max_active_slots );
      82             : 
      83             :   /* To save memory, txnpages are referenced as ushort which is enough
      84             :      to support mainnet parameters without overflow. */
      85         108 :   ushort _max_txnpages = fd_txncache_max_txnpages( max_active_slots, max_txn_per_slot );
      86         108 :   if( FD_UNLIKELY( !_max_txnpages ) ) return 0UL;
      87             : 
      88         108 :   ulong _max_txnpages_per_blockhash = fd_txncache_max_txnpages_per_blockhash( max_active_slots, max_txn_per_slot );
      89         108 :   if( FD_UNLIKELY( !_max_txnpages_per_blockhash ) ) return 0UL;
      90             : 
      91         108 :   ulong _descends_footprint = descends_set_footprint( max_active_slots );
      92         108 :   if( FD_UNLIKELY( !_descends_footprint ) ) return 0UL;
      93             : 
      94         108 :   ulong l;
      95         108 :   l = FD_LAYOUT_INIT;
      96         108 :   l = FD_LAYOUT_APPEND( l, FD_TXNCACHE_SHMEM_ALIGN,        sizeof(fd_txncache_shmem_t)                                 );
      97         108 :   l = FD_LAYOUT_APPEND( l, blockhash_map_align(),          blockhash_map_footprint( blockhash_map_chains )             );
      98         108 :   l = FD_LAYOUT_APPEND( l, blockcache_pool_align(),        blockcache_pool_footprint( max_active_slots )               );
      99         108 :   l = FD_LAYOUT_APPEND( l, alignof(ushort),                max_active_slots*_max_txnpages_per_blockhash*sizeof(ushort) ); /* blockcache->pages */
     100         108 :   l = FD_LAYOUT_APPEND( l, alignof(uint),                  max_active_slots*max_txn_per_slot*sizeof(uint)              ); /* blockcache->heads */
     101         108 :   l = FD_LAYOUT_APPEND( l, descends_set_align(),           max_active_slots*_descends_footprint                        ); /* blockcache->descends */
     102         108 :   l = FD_LAYOUT_APPEND( l, alignof(ushort),                _max_txnpages*sizeof(ushort)                                ); /* txnpages_free */
     103         108 :   l = FD_LAYOUT_APPEND( l, alignof(fd_txncache_txnpage_t), _max_txnpages*sizeof(fd_txncache_txnpage_t)                 ); /* txnpages */
     104         108 :   l = FD_LAYOUT_APPEND( l, alignof(ushort),                _max_txnpages_per_blockhash*sizeof(ushort)                  ); /* scratchpad txnpage pointer array for purge stale */
     105         108 :   l = FD_LAYOUT_APPEND( l, alignof(uint),                  max_txn_per_slot*sizeof(uint)                               ); /* scratchpad heads for purge stale */
     106         108 :   l = FD_LAYOUT_APPEND( l, alignof(fd_txncache_txnpage_t), sizeof(fd_txncache_txnpage_t)                               ); /* scratchpad txnpage for purge stale */
     107         108 :   return FD_LAYOUT_FINI( l, FD_TXNCACHE_SHMEM_ALIGN );
     108         108 : }
     109             : 
     110             : void *
     111             : fd_txncache_shmem_new( void * shmem,
     112             :                        ulong  max_live_slots,
     113             :                        ulong  max_txn_per_slot,
     114          54 :                        ulong  seed ) {
     115          54 :   if( FD_UNLIKELY( !shmem ) ) {
     116           0 :     FD_LOG_WARNING(( "NULL shmem" ));
     117           0 :     return NULL;
     118           0 :   }
     119             : 
     120          54 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_txncache_shmem_align() ) ) ) {
     121           0 :     FD_LOG_WARNING(( "misaligned shmem" ));
     122           0 :     return NULL;
     123           0 :   }
     124             : 
     125          54 :   if( FD_UNLIKELY( !max_live_slots ) ) return NULL;
     126          54 :   if( FD_UNLIKELY( !max_txn_per_slot ) ) return NULL;
     127             : 
     128          54 :   ulong max_active_slots = FD_TXNCACHE_MAX_BLOCKHASH_DISTANCE+max_live_slots;
     129          54 :   ulong blockhash_map_chains = fd_ulong_pow2_up( 2UL*max_active_slots );
     130             : 
     131          54 :   ushort _max_txnpages               = fd_txncache_max_txnpages( max_active_slots, max_txn_per_slot );
     132          54 :   ushort _max_txnpages_per_blockhash = fd_txncache_max_txnpages_per_blockhash( max_active_slots, max_txn_per_slot );
     133             : 
     134          54 :   if( FD_UNLIKELY( !_max_txnpages ) ) return NULL;
     135          54 :   if( FD_UNLIKELY( !_max_txnpages_per_blockhash ) ) return NULL;
     136             : 
     137          54 :   ulong _descends_footprint = descends_set_footprint( max_active_slots );
     138          54 :   if( FD_UNLIKELY( !_descends_footprint ) ) return NULL;
     139             : 
     140          54 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
     141          54 :   fd_txncache_shmem_t * tc    = FD_SCRATCH_ALLOC_APPEND( l, FD_TXNCACHE_SHMEM_ALIGN,         sizeof(fd_txncache_shmem_t)                                 );
     142          54 :   void * _blockhash_map       = FD_SCRATCH_ALLOC_APPEND( l, blockhash_map_align(),           blockhash_map_footprint( blockhash_map_chains )             );
     143          54 :   void * _blockcache_pool     = FD_SCRATCH_ALLOC_APPEND( l, blockcache_pool_align(),         blockcache_pool_footprint( max_active_slots )               );
     144          54 :                                 FD_SCRATCH_ALLOC_APPEND( l, alignof(ushort),                 max_active_slots*_max_txnpages_per_blockhash*sizeof(ushort) );
     145          54 :                                 FD_SCRATCH_ALLOC_APPEND( l, alignof(uint),                   max_active_slots*max_txn_per_slot*sizeof(uint)              );
     146          54 :   void * _blockcache_descends = FD_SCRATCH_ALLOC_APPEND( l, descends_set_align(),            max_active_slots*_descends_footprint                        );
     147          54 :   void * _txnpages_free       = FD_SCRATCH_ALLOC_APPEND( l, alignof(ushort),                 _max_txnpages*sizeof(ushort)                                );
     148          54 :                                 FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_txncache_txnpage_t),  _max_txnpages*sizeof(fd_txncache_txnpage_t)                 );
     149          54 :                                 FD_SCRATCH_ALLOC_APPEND( l, alignof(ushort),                 _max_txnpages_per_blockhash*sizeof(ushort)                  );
     150          54 :                                 FD_SCRATCH_ALLOC_APPEND( l, alignof(uint),                   max_txn_per_slot*sizeof(uint)                               );
     151          54 :                                 FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_txncache_txnpage_t),  sizeof(fd_txncache_txnpage_t)                               );
     152             : 
     153          54 :   fd_txncache_blockcache_shmem_t * blockcache_pool = blockcache_pool_join( blockcache_pool_new( _blockcache_pool, max_active_slots ) );
     154          54 :   FD_TEST( blockcache_pool );
     155        9216 :   for( ulong i=0UL; i<max_active_slots; i++ ) blockcache_pool[ i ].frozen = -1;
     156             : 
     157          54 :   blockhash_map_t * blockhash_map = blockhash_map_join( blockhash_map_new( _blockhash_map, blockhash_map_chains, 0UL /* seed not used */ ) );
     158          54 :   FD_TEST( blockhash_map );
     159             : 
     160        9216 :   for( ulong i=0UL; i<max_active_slots; i++ ) {
     161        9162 :     descends_set_t * descends_set = descends_set_join( descends_set_new( (uchar *)_blockcache_descends + i*_descends_footprint, max_active_slots ) );
     162        9162 :     FD_TEST( descends_set );
     163        9162 :   }
     164             : 
     165          54 :   tc->root_cnt = 0UL;
     166          54 :   FD_TEST( root_slist_join( root_slist_new( tc->root_ll ) ) );
     167             : 
     168          54 :   tc->lock->value = 0;
     169             : 
     170          54 :   tc->txn_per_slot_max           = max_txn_per_slot;
     171          54 :   tc->active_slots_max           = max_active_slots;
     172          54 :   tc->txnpages_per_blockhash_max = _max_txnpages_per_blockhash;
     173          54 :   tc->max_txnpages               = _max_txnpages;
     174             : 
     175          54 :   tc->blockcache_generation = 0U;
     176          54 :   tc->txnpages_free_cnt = _max_txnpages;
     177          54 :   ushort * txnpages_free = (ushort *)_txnpages_free;
     178       18324 :   for( ushort i=0; i<_max_txnpages; i++ ) txnpages_free[ i ] = i;
     179             : 
     180          54 :   tc->seed = seed;
     181             : 
     182          54 :   FD_COMPILER_MFENCE();
     183          54 :   FD_VOLATILE( tc->magic ) = FD_TXNCACHE_SHMEM_MAGIC;
     184          54 :   FD_COMPILER_MFENCE();
     185             : 
     186          54 :   return (void *)tc;
     187          54 : }
     188             : 
     189             : fd_txncache_shmem_t *
     190          54 : fd_txncache_shmem_join( void * shtc ) {
     191          54 :   if( FD_UNLIKELY( !shtc ) ) {
     192           0 :     FD_LOG_WARNING(( "NULL shtc" ));
     193           0 :     return NULL;
     194           0 :   }
     195             : 
     196          54 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shtc, fd_txncache_shmem_align() ) ) ) {
     197           0 :     FD_LOG_WARNING(( "misaligned shtc" ));
     198           0 :     return NULL;
     199           0 :   }
     200             : 
     201          54 :   fd_txncache_shmem_t * tc = (fd_txncache_shmem_t *)shtc;
     202             : 
     203          54 :   if( FD_UNLIKELY( tc->magic!=FD_TXNCACHE_SHMEM_MAGIC ) ) {
     204           0 :     FD_LOG_WARNING(( "bad magic" ));
     205           0 :     return NULL;
     206           0 :   }
     207             : 
     208          54 :   return tc;
     209          54 : }

Generated by: LCOV version 1.14