LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_txncache_shmem.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 34 102 33.3 %
Date: 2025-10-13 04:42:14 Functions: 4 6 66.7 %

          Line data    Source code
       1             : #include "fd_txncache_shmem.h"
       2             : #include "fd_txncache_private.h"
       3             : 
       4             : #define POOL_NAME       blockcache_pool
       5           0 : #define POOL_T          fd_txncache_blockcache_shmem_t
       6             : #define POOL_IDX_T      ulong
       7           0 : #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           0 : #define MAP_KEY                blockhash
      13           0 : #define MAP_ELE_T              fd_txncache_blockcache_shmem_t
      14             : #define MAP_KEY_T              fd_hash_t
      15           0 : #define MAP_PREV               blockhash_map.prev
      16           0 : #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           3 :                                         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           3 :   ulong result = 1UL+(max_txn_per_slot*max_active_slots)/FD_TXNCACHE_TXNS_PER_PAGE;
      41           3 :   if( FD_UNLIKELY( result>USHORT_MAX ) ) return 0;
      42           3 :   return (ushort)result;
      43           3 : }
      44             : 
      45             : FD_FN_CONST ushort
      46             : fd_txncache_max_txnpages( ulong max_active_slots,
      47           3 :                           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           3 :   ulong result = max_active_slots-1UL+max_active_slots*(1UL+(max_txn_per_slot-1UL)/FD_TXNCACHE_TXNS_PER_PAGE);
      65           3 :   if( FD_UNLIKELY( result>USHORT_MAX ) ) return 0;
      66           3 :   return (ushort)result;
      67           3 : }
      68             : 
      69             : FD_FN_CONST ulong
      70           3 : fd_txncache_shmem_align( void ) {
      71           3 :   return FD_TXNCACHE_SHMEM_ALIGN;
      72           3 : }
      73             : 
      74             : FD_FN_CONST ulong
      75             : fd_txncache_shmem_footprint( ulong max_live_slots,
      76           3 :                              ulong max_txn_per_slot ) {
      77           3 :   if( FD_UNLIKELY( max_live_slots<1UL ) ) return 0UL;
      78           3 :   if( FD_UNLIKELY( max_txn_per_slot<1UL ) ) return 0UL;
      79             : 
      80           3 :   ulong max_active_slots = FD_TXNCACHE_MAX_BLOCKHASH_DISTANCE+max_live_slots;
      81           3 :   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           3 :   ushort _max_txnpages = fd_txncache_max_txnpages( max_active_slots, max_txn_per_slot );
      86           3 :   if( FD_UNLIKELY( !_max_txnpages ) ) return 0UL;
      87             : 
      88           3 :   ulong _max_txnpages_per_blockhash = fd_txncache_max_txnpages_per_blockhash( max_active_slots, max_txn_per_slot );
      89           3 :   if( FD_UNLIKELY( !_max_txnpages_per_blockhash ) ) return 0UL;
      90             : 
      91           3 :   ulong l;
      92           3 :   l = FD_LAYOUT_INIT;
      93           3 :   l = FD_LAYOUT_APPEND( l, FD_TXNCACHE_SHMEM_ALIGN,        sizeof(fd_txncache_shmem_t)                               );
      94           3 :   l = FD_LAYOUT_APPEND( l, blockhash_map_align(),          blockhash_map_footprint( blockhash_map_chains )           );
      95           3 :   l = FD_LAYOUT_APPEND( l, blockcache_pool_align(),        blockcache_pool_footprint( max_active_slots )             );
      96           3 :   l = FD_LAYOUT_APPEND( l, alignof(uint),                  max_active_slots*_max_txnpages_per_blockhash*sizeof(uint) ); /* blockcache->pages */
      97           3 :   l = FD_LAYOUT_APPEND( l, alignof(uint),                  max_active_slots*max_txn_per_slot*sizeof(uint)            ); /* blockcache->heads */
      98           3 :   l = FD_LAYOUT_APPEND( l, alignof(uchar),                 max_active_slots*max_active_slots*sizeof(uchar)           ); /* blockcache->descends */
      99           3 :   l = FD_LAYOUT_APPEND( l, alignof(ushort),                _max_txnpages*sizeof(ushort)                              ); /* txnpages_free */
     100           3 :   l = FD_LAYOUT_APPEND( l, alignof(fd_txncache_txnpage_t), _max_txnpages*sizeof(fd_txncache_txnpage_t)               ); /* txnpages */
     101           3 :   return FD_LAYOUT_FINI( l, FD_TXNCACHE_SHMEM_ALIGN );
     102           3 : }
     103             : 
     104             : void *
     105             : fd_txncache_shmem_new( void * shmem,
     106             :                        ulong  max_live_slots,
     107           0 :                        ulong  max_txn_per_slot ) {
     108           0 :   if( FD_UNLIKELY( !shmem ) ) {
     109           0 :     FD_LOG_WARNING(( "NULL shmem" ));
     110           0 :     return NULL;
     111           0 :   }
     112             : 
     113           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_txncache_shmem_align() ) ) ) {
     114           0 :     FD_LOG_WARNING(( "misaligned shmem" ));
     115           0 :     return NULL;
     116           0 :   }
     117             : 
     118           0 :   if( FD_UNLIKELY( !max_live_slots ) ) return NULL;
     119           0 :   if( FD_UNLIKELY( !max_txn_per_slot ) ) return NULL;
     120             : 
     121           0 :   ulong max_active_slots = FD_TXNCACHE_MAX_BLOCKHASH_DISTANCE+max_live_slots;
     122           0 :   ulong blockhash_map_chains = fd_ulong_pow2_up( 2UL*max_active_slots );
     123             : 
     124           0 :   ushort _max_txnpages               = fd_txncache_max_txnpages( max_active_slots, max_txn_per_slot );
     125           0 :   ushort _max_txnpages_per_blockhash = fd_txncache_max_txnpages_per_blockhash( max_active_slots, max_txn_per_slot );
     126             : 
     127           0 :   if( FD_UNLIKELY( !_max_txnpages ) ) return NULL;
     128           0 :   if( FD_UNLIKELY( !_max_txnpages_per_blockhash ) ) return NULL;
     129             : 
     130           0 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
     131           0 :   fd_txncache_shmem_t * tc    = FD_SCRATCH_ALLOC_APPEND( l, FD_TXNCACHE_SHMEM_ALIGN,         sizeof(fd_txncache_shmem_t)                               );
     132           0 :   void * _blockhash_map       = FD_SCRATCH_ALLOC_APPEND( l, blockhash_map_align(),           blockhash_map_footprint( blockhash_map_chains )           );
     133           0 :   void * _blockcache_pool     = FD_SCRATCH_ALLOC_APPEND( l, blockcache_pool_align(),         blockcache_pool_footprint( max_active_slots )             );
     134           0 :                                 FD_SCRATCH_ALLOC_APPEND( l, alignof(uint),                   max_active_slots*_max_txnpages_per_blockhash*sizeof(uint) );
     135           0 :                                 FD_SCRATCH_ALLOC_APPEND( l, alignof(uint),                   max_active_slots*max_txn_per_slot*sizeof(uint)            );
     136           0 :                                 FD_SCRATCH_ALLOC_APPEND( l, alignof(uchar),                  max_active_slots*max_active_slots*sizeof(uchar)           );
     137           0 :   void * _txnpages_free       = FD_SCRATCH_ALLOC_APPEND( l, alignof(ushort),                 _max_txnpages*sizeof(ushort)                              );
     138           0 :                                 FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_txncache_txnpage_t),  _max_txnpages*sizeof(fd_txncache_txnpage_t)               );
     139             : 
     140           0 :   fd_txncache_blockcache_shmem_t * blockcache_pool = blockcache_pool_join( blockcache_pool_new( _blockcache_pool, max_active_slots ) );
     141           0 :   FD_TEST( blockcache_pool );
     142             : 
     143           0 :   blockhash_map_t * blockhash_map = blockhash_map_join( blockhash_map_new( _blockhash_map, blockhash_map_chains, 0UL /* seed not used */ ) );
     144           0 :   FD_TEST( blockhash_map );
     145             : 
     146           0 :   tc->root_cnt = 0UL;
     147           0 :   FD_TEST( root_slist_join( root_slist_new( tc->root_ll ) ) );
     148             : 
     149           0 :   tc->lock->value = 0;
     150             : 
     151           0 :   tc->txn_per_slot_max           = max_txn_per_slot;
     152           0 :   tc->active_slots_max           = max_active_slots;
     153           0 :   tc->txnpages_per_blockhash_max = _max_txnpages_per_blockhash;
     154           0 :   tc->max_txnpages               = _max_txnpages;
     155             : 
     156           0 :   tc->txnpages_free_cnt = _max_txnpages;
     157           0 :   ushort * txnpages_free = (ushort *)_txnpages_free;
     158           0 :   for( ushort i=0; i<_max_txnpages; i++ ) txnpages_free[ i ] = i;
     159             : 
     160           0 :   FD_COMPILER_MFENCE();
     161           0 :   FD_VOLATILE( tc->magic ) = FD_TXNCACHE_SHMEM_MAGIC;
     162           0 :   FD_COMPILER_MFENCE();
     163             : 
     164           0 :   return (void *)tc;
     165           0 : }
     166             : 
     167             : fd_txncache_shmem_t *
     168           0 : fd_txncache_shmem_join( void * shtc ) {
     169           0 :   if( FD_UNLIKELY( !shtc ) ) {
     170           0 :     FD_LOG_WARNING(( "NULL shtc" ));
     171           0 :     return NULL;
     172           0 :   }
     173             : 
     174           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shtc, fd_txncache_shmem_align() ) ) ) {
     175           0 :     FD_LOG_WARNING(( "misaligned shtc" ));
     176           0 :     return NULL;
     177           0 :   }
     178             : 
     179           0 :   fd_txncache_shmem_t * tc = (fd_txncache_shmem_t *)shtc;
     180             : 
     181           0 :   if( FD_UNLIKELY( tc->magic!=FD_TXNCACHE_SHMEM_MAGIC ) ) {
     182           0 :     FD_LOG_WARNING(( "bad magic" ));
     183           0 :     return NULL;
     184           0 :   }
     185             : 
     186           0 :   return tc;
     187           0 : }

Generated by: LCOV version 1.14