LCOV - code coverage report
Current view: top level - disco/store - fd_store.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 131 189 69.3 %
Date: 2026-03-31 06:22:16 Functions: 11 14 78.6 %

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

Generated by: LCOV version 1.14