LCOV - code coverage report
Current view: top level - disco/store - fd_store.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 143 191 74.9 %
Date: 2026-05-12 06:58:09 Functions: 11 14 78.6 %

          Line data    Source code
       1             : #include "fd_store.h"
       2             : 
       3             : static inline fd_store_map_t *
       4         330 : map_laddr( fd_store_t * store ) {
       5         330 :   return fd_wksp_laddr_fast( fd_store_wksp( store ), store->map_gaddr );
       6         330 : }
       7             : 
       8             : static inline fd_store_pool_t
       9         516 : pool_ljoin( fd_store_t const * store ) {
      10         516 :   return (fd_store_pool_t){
      11         516 :       .pool    = fd_wksp_laddr_fast( fd_store_wksp( store ), store->pool_mem_gaddr ),
      12         516 :       .ele     = fd_wksp_laddr_fast( fd_store_wksp( store ), store->pool_ele_gaddr ),
      13         516 :       .ele_max = store->fec_max };
      14         516 : }
      15             : 
      16             : static inline fd_store_fec_t *
      17         324 : pool_laddr( fd_store_t * store ) {
      18         324 :   fd_store_pool_t pool = pool_ljoin( store );
      19         324 :   return pool.ele;
      20         324 : }
      21             : 
      22             : void *
      23             : fd_store_new( void * shmem,
      24             :               ulong  part_cnt,
      25             :               ulong  fec_max,
      26          18 :               ulong  fec_data_max ) {
      27             : 
      28          18 :   if( FD_UNLIKELY( part_cnt==0UL ) ) {
      29           0 :     FD_LOG_WARNING(( "part_cnt must be non-zero" ));
      30           0 :     return NULL;
      31           0 :   }
      32             : 
      33          18 :   if( FD_UNLIKELY( !shmem ) ) {
      34           0 :     FD_LOG_WARNING(( "NULL mem" ));
      35           0 :     return NULL;
      36           0 :   }
      37             : 
      38          18 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_store_align() ) ) ) {
      39           0 :     FD_LOG_WARNING(( "misaligned mem" ));
      40           0 :     return NULL;
      41           0 :   }
      42             : 
      43          18 :   ulong footprint = fd_store_footprint( fec_max, fec_data_max );
      44             : 
      45          18 :   fd_wksp_t * wksp = fd_wksp_containing( shmem );
      46          18 :   if( FD_UNLIKELY( !wksp ) ) {
      47           0 :     FD_LOG_WARNING(( "shmem must be part of a workspace" ));
      48           0 :     return NULL;
      49           0 :   }
      50             : 
      51             :   /* The seed is derived from the number of chains in the map.  The
      52             :      number of chains is estimated from fec_max (via chain_cnt_est) and
      53             :      is always a power of two.  The size of each partition is chain_cnt
      54             :      / part_cnt.  We use the per partition slot count as the seed so
      55             :      that the modified hash function can hash the key into the correct
      56             :      partition. */
      57             : 
      58          18 :   ulong chain_cnt     = fd_store_map_chain_cnt_est( fec_max );
      59          18 :   ulong part_slot_cnt = chain_cnt / part_cnt;
      60          18 :   ulong seed          = part_slot_cnt;
      61             : 
      62          18 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
      63          18 :   fd_store_t * store    = FD_SCRATCH_ALLOC_APPEND( l, fd_store_align(),        sizeof(fd_store_t)                   );
      64          18 :   void *       map      = FD_SCRATCH_ALLOC_APPEND( l, fd_store_map_align(),    fd_store_map_footprint( chain_cnt ) );
      65          18 :   void *       shpool   = FD_SCRATCH_ALLOC_APPEND( l, fd_store_pool_align(),   fd_store_pool_footprint()            );
      66          18 :   void *       shele    = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_store_fec_t), sizeof(fd_store_fec_t)*fec_max       );
      67          18 :   uchar *      data     = FD_SCRATCH_ALLOC_APPEND( l, FD_STORE_ALIGN,          fec_data_max*fec_max                 );
      68          18 :   FD_TEST( FD_SCRATCH_ALLOC_FINI( l, fd_store_align() )==(ulong)shmem + footprint );
      69             : 
      70          18 :   fd_memset( store, 0, sizeof(fd_store_t) );
      71          18 :   store->part_cnt       = part_cnt;
      72          18 :   store->fec_max        = fec_max;
      73          18 :   store->fec_data_max   = fec_data_max;
      74          18 :   store->store_gaddr    = fd_wksp_gaddr_fast( wksp, store );
      75          18 :   store->map_gaddr      = fd_wksp_gaddr_fast( wksp, fd_store_map_join( fd_store_map_new( map, chain_cnt, seed ) ) );
      76          18 :   store->pool_mem_gaddr = fd_wksp_gaddr_fast( wksp, shpool   );
      77          18 :   store->pool_ele_gaddr = fd_wksp_gaddr_fast( wksp, shele    );
      78          18 :   store->data_gaddr     = fd_wksp_gaddr_fast( wksp, data );
      79             : 
      80          18 :   if( FD_UNLIKELY( !fd_store_pool_new( shpool ) ) ) {
      81           0 :     FD_LOG_WARNING(( "fd_store_pool_new failed" ));
      82           0 :     return NULL;
      83           0 :   }
      84          18 :   fd_store_pool_t pool_ljoin;
      85          18 :   fd_store_pool_reset( fd_store_pool_join( &pool_ljoin, shpool, shele, fec_max ) );
      86             : 
      87             :   /* Set each element's data_gaddr to point to its slice of the
      88             :      contiguous data buffer region. */
      89             : 
      90          18 :   fd_store_fec_t * fec0 = (fd_store_fec_t *)shele;
      91         378 :   for( ulong i=0UL; i<fec_max; i++ ) {
      92         360 :     fec0[ i ].data_gaddr = fd_wksp_gaddr_fast( wksp, data + i*fec_data_max );
      93         360 :   }
      94             : 
      95          18 :   FD_COMPILER_MFENCE();
      96          18 :   FD_VOLATILE( store->magic ) = FD_STORE_MAGIC;
      97          18 :   FD_COMPILER_MFENCE();
      98             : 
      99          18 :   return shmem;
     100          18 : }
     101             : 
     102             : fd_store_t *
     103          18 : fd_store_join( void * shstore ) {
     104             : 
     105          18 :   if( FD_UNLIKELY( !shstore ) ) {
     106           0 :     FD_LOG_WARNING(( "NULL store" ));
     107           0 :     return NULL;
     108           0 :   }
     109             : 
     110          18 :   if( FD_UNLIKELY( !fd_ulong_is_aligned((ulong)shstore, fd_store_align() ) ) ) {
     111           0 :     FD_LOG_WARNING(( "misaligned store" ));
     112           0 :     return NULL;
     113           0 :   }
     114             : 
     115          18 :   fd_wksp_t * wksp = fd_wksp_containing( shstore );
     116          18 :   if( FD_UNLIKELY( !wksp ) ) {
     117           0 :     FD_LOG_WARNING(( "store must be part of a workspace" ));
     118           0 :     return NULL;
     119           0 :   }
     120             : 
     121          18 :   fd_store_t * store = (fd_store_t *)shstore;
     122          18 :   if( FD_UNLIKELY( store->magic!=FD_STORE_MAGIC ) ) {
     123           0 :     FD_LOG_WARNING(( "bad magic" ));
     124           0 :     return NULL;
     125           0 :   }
     126             : 
     127          18 :   return store;
     128          18 : }
     129             : 
     130             : void *
     131          12 : fd_store_leave( fd_store_t const * store ) {
     132             : 
     133          12 :   if( FD_UNLIKELY( !store ) ) {
     134           0 :     FD_LOG_WARNING(( "NULL store" ));
     135           0 :     return NULL;
     136           0 :   }
     137             : 
     138          12 :   return (void *)store;
     139          12 : }
     140             : 
     141             : void *
     142          12 : fd_store_delete( void * shstore ) {
     143             : 
     144          12 :   if( FD_UNLIKELY( !shstore ) ) {
     145           0 :     FD_LOG_WARNING(( "NULL store" ));
     146           0 :     return NULL;
     147           0 :   }
     148             : 
     149          12 :   if( FD_UNLIKELY( !fd_ulong_is_aligned((ulong)shstore, fd_store_align() ) ) ) {
     150           0 :     FD_LOG_WARNING(( "misaligned store" ));
     151           0 :     return NULL;
     152           0 :   }
     153             : 
     154          12 :   fd_store_t * store = (fd_store_t *)shstore;
     155          12 :   if( FD_UNLIKELY( store->magic!=FD_STORE_MAGIC ) ) {
     156           0 :     FD_LOG_WARNING(( "bad magic" ));
     157           0 :     return NULL;
     158           0 :   }
     159             : 
     160          12 :   FD_COMPILER_MFENCE();
     161          12 :   FD_VOLATILE( store->magic ) = 0UL;
     162          12 :   FD_COMPILER_MFENCE();
     163             : 
     164          12 :   return shstore;
     165          12 : }
     166             : 
     167             : fd_store_fec_t *
     168             : fd_store_query( fd_store_t       * store,
     169          78 :                 fd_hash_t  const * merkle_root ) {
     170             : 
     171          78 :   fd_store_pool_t pool = pool_ljoin( store );
     172          78 :   ulong           null = fd_store_pool_idx_null();
     173          84 :   for( uint part_idx = 0; part_idx < store->part_cnt; part_idx++ ) {
     174          81 :     fd_store_key_t   key = { *merkle_root, part_idx };
     175          81 :     ulong            idx = fd_store_map_idx_query_const( map_laddr( store ), &key, null, pool_laddr( store ) );
     176          81 :     fd_store_fec_t * fec = fd_store_pool_ele( &pool, idx );
     177          81 :     if( FD_LIKELY( fec ) ) return fec;
     178          81 :   }
     179           3 :   return NULL;
     180          78 : }
     181             : 
     182             : fd_store_fec_t *
     183             : fd_store_insert( fd_store_t * store,
     184             :                  ulong        part_idx,
     185          90 :                  fd_hash_t  * merkle_root ) {
     186             : 
     187          90 :   fd_store_pool_t pool = pool_ljoin( store );
     188          90 :   ulong           null = fd_store_pool_idx_null();
     189             : 
     190         225 :   for( ulong part_idx = 0; part_idx < store->part_cnt; part_idx++ ) {
     191         141 :     fd_store_key_t key = { *merkle_root, part_idx };
     192         141 :     ulong          idx = null;
     193             : 
     194         141 :     FD_STORE_SLOCK_BEGIN( store ) {
     195         141 :       idx = fd_store_map_idx_query_const( map_laddr( store ), &key, null, pool_laddr( store ) );
     196         141 :     } FD_STORE_SLOCK_END;
     197             : 
     198         141 :     fd_store_fec_t * fec = fd_store_pool_ele( &pool, idx );
     199         141 :     if( FD_UNLIKELY( fec ) ) return fec;
     200         141 :   }
     201             : 
     202          84 :   fd_store_fec_t * fec = fd_store_pool_acquire( &pool );
     203          84 :   if( FD_UNLIKELY( !fec ) ) FD_LOG_CRIT(( "fd_store_pool_acquire failed" ));
     204          84 :   fec->key.merkle_root = *merkle_root;
     205          84 :   fec->key.part_idx    = part_idx;
     206          84 :   fec->cmr             = (fd_hash_t){ 0 };
     207          84 :   fec->next            = null;
     208          84 :   fec->data_sz         = 0UL;
     209             : 
     210          84 :   FD_STORE_SLOCK_BEGIN( store ) {
     211          84 :     fd_store_map_ele_insert( map_laddr( store ), fec, pool_laddr( store ) );
     212          84 :   } FD_STORE_SLOCK_END;
     213             : 
     214          84 :   return fec;
     215          84 : }
     216             : 
     217             : void
     218             : fd_store_remove( fd_store_t      * store,
     219           6 :                  fd_hash_t const * merkle_root ) {
     220             : 
     221           6 :   fd_store_pool_t pool = pool_ljoin( store );
     222           9 :   for( uint part_idx = 0; part_idx < store->part_cnt; part_idx++ ) {
     223           6 :     fd_store_key_t   key = { *merkle_root, part_idx };
     224           6 :     fd_store_fec_t * fec = NULL;
     225             : 
     226           6 :     FD_STORE_XLOCK_BEGIN( store ) {
     227           6 :       fec = fd_store_map_ele_remove( map_laddr( store ), &key, NULL, pool_laddr( store ) );
     228           6 :     } FD_STORE_XLOCK_END;
     229           6 :     if( FD_UNLIKELY( !fec ) ) continue;
     230             : 
     231           3 :     fd_store_pool_release( &pool, fec );
     232           3 :     return;
     233           6 :   }
     234             : 
     235           3 :   FD_BASE58_ENCODE_32_BYTES( merkle_root->uc, _merkle_root );
     236           3 :   FD_LOG_WARNING(( "key not found %s", _merkle_root ));
     237           3 : }
     238             : 
     239             : int
     240           9 : fd_store_verify( fd_store_t * store ) {
     241             : 
     242           9 :   fd_store_map_t * map  = map_laddr( store );
     243           9 :   fd_store_fec_t * fec0 = pool_laddr( store );
     244             : 
     245           9 :   ulong part_sz = map->chain_cnt / store->part_cnt;
     246           9 :   if( part_sz != map->seed ) {
     247           0 :     FD_LOG_WARNING(( "part_sz (%lu) != map->seed (%lu)", part_sz, map->seed ));
     248           0 :     return -1;
     249           0 :   }
     250             : 
     251             :   /* Iterate the map and check slots are partitioned correctly. */
     252             : 
     253           9 :   for( fd_store_map_iter_t iter = fd_store_map_iter_init(       map, fec0 );
     254          21 :                                  !fd_store_map_iter_done( iter, map, fec0 );
     255          12 :                            iter = fd_store_map_iter_next( iter, map, fec0 ) ) {
     256          12 :     fd_store_fec_t const * fec = fd_store_map_iter_ele_const( iter, map, fec0 );
     257          12 :     if( FD_UNLIKELY( !fec ) ) {
     258           0 :       FD_LOG_WARNING(( "NULL ele" ));
     259           0 :       return -1;
     260           0 :     }
     261          12 :     ulong chain_idx = fd_store_map_private_chain_idx( &fec->key, map->seed, map->chain_cnt );
     262          12 :     ulong k         = fec->key.part_idx;
     263          12 :     ulong n         = part_sz;
     264          12 :     if( FD_UNLIKELY( chain_idx < k * n || chain_idx >= (k + 1) * n ) ) { /* chain_idx in [k*n, (k+1)*n) */
     265           0 :       FD_LOG_WARNING(( "chain_idx %lu not in range [%lu, %lu)", chain_idx, k * n, (k + 1) * n ) );
     266           0 :       return -1;
     267           0 :     }
     268          12 :   }
     269           9 :   fd_store_pool_t pool = pool_ljoin( store );
     270           9 :   if( FD_UNLIKELY( fd_store_pool_verify( &pool )==-1 ) ) return -1;
     271           9 :   return fd_store_map_verify( map, store->fec_max, fec0 );
     272           9 : }

Generated by: LCOV version 1.14