LCOV - code coverage report
Current view: top level - disco/store - fd_store.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 187 250 74.8 %
Date: 2025-10-27 04:40:00 Functions: 11 11 100.0 %

          Line data    Source code
       1             : #include "fd_store.h"
       2             : #include "../../flamenco/fd_flamenco_base.h"
       3             : 
       4             : static const fd_hash_t hash_null = { 0 };
       5             : 
       6         303 : #define null fd_store_pool_idx_null()
       7             : 
       8          90 : #define BLOCKING 1
       9             : 
      10             : void *
      11           9 : fd_store_new( void * shmem, ulong fec_max, ulong part_cnt ) {
      12             : 
      13           9 :   if( FD_UNLIKELY( part_cnt==0UL ) ) {
      14           0 :     FD_LOG_WARNING(( "partition count must be greater than 0, should match the number of writers/shred tiles" ));
      15           0 :     return NULL;
      16           0 :   }
      17             : 
      18           9 :   if( FD_UNLIKELY( !shmem ) ) {
      19           0 :     FD_LOG_WARNING(( "NULL mem" ));
      20           0 :     return NULL;
      21           0 :   }
      22             : 
      23           9 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_store_align() ) ) ) {
      24           0 :     FD_LOG_WARNING(( "misaligned mem" ));
      25           0 :     return NULL;
      26           0 :   }
      27             : 
      28           9 :   ulong footprint = fd_store_footprint( fec_max );
      29           9 :   if( FD_UNLIKELY( !footprint ) ) {
      30           0 :     FD_LOG_WARNING(( "bad fec_max (%lu)", fec_max ));
      31           0 :     return NULL;
      32           0 :   }
      33             : 
      34           9 :   fd_wksp_t * wksp = fd_wksp_containing( shmem );
      35           9 :   if( FD_UNLIKELY( !wksp ) ) {
      36           0 :     FD_LOG_WARNING(( "shmem must be part of a workspace" ));
      37           0 :     return NULL;
      38           0 :   }
      39             : 
      40             :   /* This seed value is very important. We have fec_max chains in the
      41             :      map, which means the size of each partition of buckets should be
      42             :      fec_max / part_cnt. When inserting into the map, we use the
      43             :      partition_slot_cnt as the seed, so that the modified hash function
      44             :      can use the seed/partition_slot_cnt to hash the key into the
      45             :      correct partition. */
      46             : 
      47           9 :   ulong part_slot_cnt = fec_max / part_cnt;
      48           9 :   ulong seed          = part_slot_cnt;
      49             : 
      50           9 :   FD_SCRATCH_ALLOC_INIT( l, shmem );
      51           9 :   fd_store_t * store  = FD_SCRATCH_ALLOC_APPEND( l, fd_store_align(),        sizeof(fd_store_t)                 );
      52           9 :   void *       map    = FD_SCRATCH_ALLOC_APPEND( l, fd_store_map_align(),    fd_store_map_footprint ( fec_max ) );
      53           9 :   void *       shpool = FD_SCRATCH_ALLOC_APPEND( l, fd_store_pool_align(),   fd_store_pool_footprint()          );
      54           9 :   void *       shele  = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_store_fec_t), sizeof(fd_store_fec_t)*fec_max     );
      55           9 :   FD_TEST( FD_SCRATCH_ALLOC_FINI( l, fd_store_align() ) == (ulong)shmem + footprint );
      56             : 
      57           9 :   fd_memset( store, 0, sizeof(fd_store_t) );
      58           9 :   store->store_gaddr    = fd_wksp_gaddr_fast( wksp, store  );
      59           9 :   store->pool_mem_gaddr = fd_wksp_gaddr_fast( wksp, shpool );
      60           9 :   store->pool_ele_gaddr = fd_wksp_gaddr_fast( wksp, shele  );
      61           9 :   store->map_gaddr      = fd_wksp_gaddr_fast( wksp, fd_store_map_join( fd_store_map_new ( map, fec_max, seed ) ) );
      62             : 
      63           9 :   store->part_cnt = part_cnt;
      64           9 :   store->fec_max  = fec_max;
      65           9 :   store->root     = null;
      66             : 
      67           9 :   fd_store_pool_t pool = fd_store_pool( store );
      68           9 :   if( FD_UNLIKELY( !fd_store_pool_new( shpool ) ) ) {
      69           0 :     FD_LOG_WARNING(( "fd_store_pool_new failed" ));
      70           0 :     return NULL;
      71           0 :   }
      72           9 :   fd_store_pool_reset( &pool, 0 );
      73             : 
      74           9 :   FD_COMPILER_MFENCE();
      75           9 :   FD_VOLATILE( store->magic ) = FD_STORE_MAGIC;
      76           9 :   FD_COMPILER_MFENCE();
      77             : 
      78           9 :   return shmem;
      79           9 : }
      80             : 
      81             : fd_store_t *
      82           9 : fd_store_join( void * shstore ) {
      83             : 
      84           9 :   if( FD_UNLIKELY( !shstore ) ) {
      85           0 :     FD_LOG_WARNING(( "NULL store" ));
      86           0 :     return NULL;
      87           0 :   }
      88             : 
      89           9 :   if( FD_UNLIKELY( !fd_ulong_is_aligned((ulong)shstore, fd_store_align() ) ) ) {
      90           0 :     FD_LOG_WARNING(( "misaligned store" ));
      91           0 :     return NULL;
      92           0 :   }
      93             : 
      94           9 :   fd_wksp_t * wksp = fd_wksp_containing( shstore );
      95           9 :   if( FD_UNLIKELY( !wksp ) ) {
      96           0 :     FD_LOG_WARNING(( "store must be part of a workspace" ));
      97           0 :     return NULL;
      98           0 :   }
      99             : 
     100           9 :   fd_store_t * store = (fd_store_t *)shstore;
     101           9 :   if( FD_UNLIKELY( store->magic!=FD_STORE_MAGIC ) ) {
     102           0 :     FD_LOG_WARNING(( "bad magic" ));
     103           0 :     return NULL;
     104           0 :   }
     105             : 
     106           9 :   return store;
     107           9 : }
     108             : 
     109             : void *
     110           3 : fd_store_leave( fd_store_t const * store ) {
     111             : 
     112           3 :   if( FD_UNLIKELY( !store ) ) {
     113           0 :     FD_LOG_WARNING(( "NULL store" ));
     114           0 :     return NULL;
     115           0 :   }
     116             : 
     117           3 :   return (void *)store;
     118           3 : }
     119             : 
     120             : void *
     121           3 : fd_store_delete( void * shstore ) {
     122             : 
     123           3 :   if( FD_UNLIKELY( !shstore ) ) {
     124           0 :     FD_LOG_WARNING(( "NULL store" ));
     125           0 :     return NULL;
     126           0 :   }
     127             : 
     128           3 :   if( FD_UNLIKELY( !fd_ulong_is_aligned((ulong)shstore, fd_store_align() ) ) ) {
     129           0 :     FD_LOG_WARNING(( "misaligned store" ));
     130           0 :     return NULL;
     131           0 :   }
     132             : 
     133           3 :   fd_store_t * store = (fd_store_t *)shstore;
     134           3 :   if( FD_UNLIKELY( store->magic!=FD_STORE_MAGIC ) ) {
     135           0 :     FD_LOG_WARNING(( "bad magic" ));
     136           0 :     return NULL;
     137           0 :   }
     138             : 
     139           3 :   FD_COMPILER_MFENCE();
     140           3 :   FD_VOLATILE( store->magic ) = 0UL;
     141           3 :   FD_COMPILER_MFENCE();
     142             : 
     143           3 :   return shstore;
     144           3 : }
     145             : 
     146             : fd_store_fec_t *
     147             : fd_store_insert( fd_store_t * store,
     148             :                  ulong        part_idx,
     149          54 :                  fd_hash_t  * merkle_root ) {
     150          54 :   if( FD_UNLIKELY( fd_store_query_const( store, merkle_root ) ) ) {
     151           3 :     FD_LOG_WARNING(( "Merkle root %s already in store.  Ignoring insert.", FD_BASE58_ENC_32_ALLOCA( merkle_root ) ));
     152           3 :     return NULL;
     153           3 :   }
     154             : 
     155          51 :   int err;
     156          51 :   fd_store_pool_t  pool = fd_store_pool( store );
     157          51 :   fd_store_fec_t * fec  = fd_store_pool_acquire( &pool, NULL, BLOCKING, &err );
     158             : 
     159          51 :   if( FD_UNLIKELY( err == FD_POOL_ERR_EMPTY   ) ) { FD_LOG_WARNING(( "store full %s",    fd_store_pool_strerror( err ) )); return NULL; } /* FIXME: eviction? max bound guaranteed for worst-case? */
     160          51 :   if( FD_UNLIKELY( err == FD_POOL_ERR_CORRUPT ) ) { FD_LOG_CRIT   (( "store corrupt %s", fd_store_pool_strerror( err ) )); }
     161          51 :   FD_TEST( fec );
     162             : 
     163          51 :   fec->key.mr           = *merkle_root;
     164          51 :   fec->key.part         = part_idx;
     165          51 :   fec->cmr              = hash_null;
     166          51 :   fec->next             = null;
     167          51 :   fec->parent           = null;
     168          51 :   fec->child            = null;
     169          51 :   fec->sibling          = null;
     170          51 :   fec->data_sz          = 0UL;
     171          51 :   if( FD_UNLIKELY( store->root == null ) ) store->root = fd_store_pool_idx( &pool, fec );
     172          51 :   fd_store_map_ele_insert( fd_store_map( store ), fec, fd_store_fec0( store ) );
     173             : 
     174          51 :   return fec;
     175          51 : }
     176             : 
     177             : fd_store_fec_t *
     178          39 : fd_store_link( fd_store_t * store, fd_hash_t * merkle_root, fd_hash_t * chained_merkle_root ) {
     179             : 
     180          39 : # if FD_STORE_USE_HANDHOLDING
     181          39 :   if( FD_UNLIKELY( !fd_store_query_const( store, merkle_root         ) ) ) { FD_LOG_WARNING(( "missing merkle root %s",         FD_BASE58_ENC_32_ALLOCA( merkle_root         ) ) ); return NULL; }
     182          39 :   if( FD_UNLIKELY( !fd_store_query_const( store, chained_merkle_root ) ) ) { FD_LOG_WARNING(( "missing chained merkle root %s", FD_BASE58_ENC_32_ALLOCA( chained_merkle_root ) ) ); return NULL; }
     183          39 : # endif
     184             : 
     185          39 :   fd_store_pool_t   pool   = fd_store_pool( store );
     186          39 :   fd_store_fec_t  * parent = fd_store_query( store, chained_merkle_root );
     187          39 :   fd_store_fec_t  * child  = fd_store_query( store, merkle_root );
     188             : 
     189          39 :   if( FD_UNLIKELY( child->parent != null ) ) return child; /* already linked */
     190          39 :   child->parent = fd_store_pool_idx( &pool, parent );
     191          39 :   if( FD_LIKELY( parent->child == null ) ) {
     192          36 :     parent->child = fd_store_pool_idx( &pool, child ); /* set as left-child. */
     193          36 :   } else {
     194           3 :     fd_store_fec_t * curr = fd_store_pool_ele( &pool, parent->child );
     195           3 :     while( curr->sibling != null ) curr = fd_store_pool_ele( &pool, curr->sibling );
     196           3 :     curr->sibling = fd_store_pool_idx( &pool, child ); /* set as right-sibling. */
     197           3 :   }
     198          39 :   return child;
     199          39 : }
     200             : 
     201             : fd_store_fec_t *
     202             : fd_store_publish( fd_store_t *      store,
     203           3 :                   fd_hash_t const * merkle_root ) {
     204             : 
     205           3 : # if FD_STORE_USE_HANDHOLDING
     206           3 :   if( FD_UNLIKELY( !fd_store_query( store, merkle_root ) ) ) { FD_LOG_WARNING(( "merkle root %s not found", FD_BASE58_ENC_32_ALLOCA( merkle_root ) )); return NULL; }
     207           3 : # endif
     208             : 
     209           3 :   fd_store_map_t  * map  = fd_store_map ( store );
     210           3 :   fd_store_pool_t   pool = fd_store_pool( store );
     211           3 :   fd_store_fec_t  * fec0 = fd_store_fec0( store );
     212           3 :   fd_store_fec_t  * oldr = fd_store_root( store );
     213           3 :   fd_store_fec_t  * newr = fd_store_query( store, merkle_root );
     214             : 
     215             :   /* First, remove the previous root, and push it as the first element
     216             :      of the BFS queue. */
     217             : 
     218           3 :   fd_store_fec_t * head = fd_store_map_ele_remove( map, &oldr->key, NULL, fec0 );
     219           3 :   head->next            = null; /* clear map next */
     220           3 :   fd_store_fec_t * tail = head; /* tail of BFS queue */
     221             : 
     222             :   /* Second, BFS down the tree, pruning all of root's ancestors and also
     223             :      any descendants of those ancestors. */
     224             : 
     225          42 :   while( FD_LIKELY( head ) ) {
     226          39 :     fd_store_fec_t * child = fd_store_pool_ele( &pool, head->child );         /* left-child */
     227          78 :     while( FD_LIKELY( child ) ) {                                             /* iterate over children */
     228          39 :       if( FD_LIKELY( child != newr ) ) {                                      /* stop at new root */
     229          36 :         tail->next = fd_store_map_idx_remove( map, &child->key, null, fec0 ); /* remove node from map to reuse `.next` */
     230          36 :         tail       = fd_store_pool_ele( &pool, tail->next );                  /* push onto BFS queue (so descendants can be pruned) */
     231          36 :         tail->next = null;                                                    /* clear map next */
     232          36 :       }
     233          39 :       child = fd_store_pool_ele( &pool, child->sibling );                     /* right-sibling */
     234          39 :     }
     235          39 :     fd_store_fec_t * next = fd_store_pool_ele( &pool, head->next ); /* pophead */
     236          39 :     int err = fd_store_pool_release( &pool, head, BLOCKING );       /* release */
     237          39 :     if( FD_UNLIKELY( err != FD_POOL_SUCCESS ) ) {
     238           0 :       FD_LOG_WARNING(( "failed to release fec %s", fd_store_pool_strerror( err ) ));
     239           0 :       return NULL;
     240           0 :     }
     241          39 :     head = next;                                                    /* advance */
     242          39 :   }
     243           3 :   newr->parent = null;                             /* unlink old root */
     244           3 :   store->root  = fd_store_pool_idx( &pool, newr ); /* replace with new root */
     245           3 :   return newr;
     246           3 : }
     247             : 
     248             : fd_store_t *
     249           3 : fd_store_clear( fd_store_t * store ) {
     250             : 
     251           3 : # if FD_STORE_USE_HANDHOLDING
     252           3 :   if( FD_UNLIKELY( !fd_store_root( store ) ) ) { FD_LOG_WARNING(( "calling clear on an empty store" )); return NULL; }
     253           3 : # endif
     254             : 
     255           3 :   fd_store_map_t * map  = fd_store_map( store );
     256           3 :   fd_store_pool_t  pool = fd_store_pool( store );
     257           3 :   fd_store_fec_t * fec0 = fd_store_fec0( store );
     258             : 
     259           3 :   fd_store_fec_t * head = fd_store_root( store );
     260           3 :   fd_store_fec_t * tail = head;
     261             : 
     262           3 :   for( fd_store_map_iter_t iter = fd_store_map_iter_init( map, fec0 );
     263           6 :        !fd_store_map_iter_done( iter, map, fec0 );
     264           3 :        iter = fd_store_map_iter_next( iter, map, fec0 ) ) {
     265           3 :     ulong idx = fd_store_map_iter_idx( iter, map, fec0 );
     266           3 :     if( FD_UNLIKELY( idx == fd_store_pool_idx( &pool, head ) ) ) continue;
     267           0 :     tail->sibling = idx;
     268           0 :     tail          = fd_store_pool_ele( &pool, tail->sibling );
     269           0 :   }
     270           3 :   tail->sibling = null;
     271           3 :   for( ulong idx = fd_store_pool_idx( &pool, head );
     272           6 :        FD_LIKELY( idx != null );
     273           3 :        idx = fd_store_pool_ele( &pool, idx )->sibling ) {
     274           3 :     fd_store_fec_t * fec = fd_store_pool_ele( &pool, idx );
     275           3 :     fd_store_map_idx_remove( map, &fec->key, null, fec0 );
     276           3 :     fd_store_pool_release( &pool, fec, 1 );
     277           3 :   }
     278           3 :   store->root = null;
     279           3 :   return store;
     280           3 : }
     281             : 
     282             : int
     283           3 : fd_store_verify( fd_store_t * store ) {
     284             : 
     285           3 :   fd_store_map_t * map  = fd_store_map( store );
     286           3 :   fd_store_fec_t * fec0 = fd_store_fec0( store );
     287             : 
     288           3 :   ulong part_sz = store->fec_max / store->part_cnt;
     289           3 :   if( part_sz != map->seed ) {
     290           0 :     FD_LOG_WARNING(( "part_sz (%lu) != map->seed (%lu)", part_sz, map->seed ));
     291           0 :     return -1;
     292           0 :   }
     293             : 
     294             :   /* iter the map, check that the partitions are correct */
     295             : 
     296           3 :   for( fd_store_map_iter_t iter = fd_store_map_iter_init( map, fec0 ); !fd_store_map_iter_done( iter, map, fec0 ); iter = fd_store_map_iter_next( iter, map, fec0 ) ) {
     297           0 :     fd_store_fec_t const * fec = fd_store_map_iter_ele_const( iter, map, fec0 );
     298           0 :     if( FD_UNLIKELY( !fec ) ) {
     299           0 :       FD_LOG_WARNING(( "NULL ele" ));
     300           0 :       return -1;
     301           0 :     }
     302           0 :     ulong chain_idx = fd_store_map_private_chain_idx( &fec->key, map->seed, map->chain_cnt );
     303             :     /* the chain_idx should be in the range of the partition */
     304           0 :     if( FD_UNLIKELY( chain_idx < part_sz * fec->key.part || chain_idx >= part_sz * (fec->key.part + 1) ) ) {
     305           0 :       FD_LOG_WARNING(( "chain_idx %lu not in range %lu-%lu", chain_idx, part_sz * fec->key.part, part_sz * (fec->key.part + 1) ) );
     306           0 :       return -1;
     307           0 :     }
     308           0 :   }
     309           3 :   fd_store_pool_t pool = fd_store_pool( store );
     310           3 :   if( FD_UNLIKELY( fd_store_pool_verify( &pool )==-1 ) ) return -1;
     311           3 :   return fd_store_map_verify( map, store->fec_max, fec0 );
     312           3 : }
     313             : 
     314             : #include <stdio.h>
     315             : 
     316             : static void
     317          42 : print( fd_store_t const * store, fd_store_fec_t const * fec, int space, const char * prefix ) {
     318             : 
     319          42 :   if( fec == NULL ) return;
     320          42 :   if( space > 0 ) printf( "\n" );
     321         798 :   for( int i = 0; i < space; i++ ) printf( " " );
     322          42 :   printf( "%s%s", prefix, FD_BASE58_ENC_32_ALLOCA( &fec->key.mr ) );
     323             : 
     324           0 :   fd_store_pool_t pool = fd_store_pool( store );
     325          42 :   fd_store_fec_t const * curr = fd_store_pool_ele_const( &pool, fec->child );
     326          42 :   char new_prefix[1024]; /* FIXME size this correctly */
     327          81 :   while( curr ) {
     328          39 :     if( fd_store_pool_ele_const( &pool, curr->sibling ) ) {
     329           3 :       sprintf( new_prefix, "├── " ); /* branch indicating more siblings follow */
     330           3 :       print( store, curr, space + 4, new_prefix );
     331          36 :     } else {
     332          36 :       sprintf( new_prefix, "└── " ); /* end branch */
     333          36 :       print( store, curr, space + 4, new_prefix );
     334          36 :     }
     335          39 :     curr = fd_store_pool_ele_const( &pool, curr->sibling );
     336          39 :   }
     337          42 : }
     338             : 
     339             : void
     340           3 : fd_store_print( fd_store_t const * store ) {
     341           3 :   FD_LOG_NOTICE( ( "\n\n[Store]" ) );
     342           3 :   print( store, fd_store_root_const( store ), 0, "" );
     343             :   printf( "\n\n" );
     344           3 : }

Generated by: LCOV version 1.14