LCOV - code coverage report
Current view: top level - flamenco/accdb - fd_accdb_admin.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 260 290 89.7 %
Date: 2025-12-27 05:04:59 Functions: 16 16 100.0 %

          Line data    Source code
       1             : #include "fd_accdb_admin.h"
       2             : 
       3             : fd_accdb_admin_t *
       4             : fd_accdb_admin_join( fd_accdb_admin_t * ljoin,
       5          63 :                      void *             shfunk ) {
       6          63 :   if( FD_UNLIKELY( !ljoin ) ) {
       7           0 :     FD_LOG_WARNING(( "NULL ljoin" ));
       8           0 :     return NULL;
       9           0 :   }
      10          63 :   if( FD_UNLIKELY( !shfunk ) ) {
      11           0 :     FD_LOG_WARNING(( "NULL shfunk" ));
      12           0 :     return NULL;
      13           0 :   }
      14             : 
      15          63 :   memset( ljoin, 0, sizeof(fd_accdb_admin_t) );
      16          63 :   if( FD_UNLIKELY( !fd_funk_join( ljoin->funk, shfunk ) ) ) {
      17           0 :     FD_LOG_CRIT(( "fd_funk_join failed" ));
      18           0 :   }
      19             : 
      20          63 :   return ljoin;
      21          63 : }
      22             : 
      23             : void *
      24             : fd_accdb_admin_leave( fd_accdb_admin_t * admin,
      25          60 :                       void **            opt_shfunk ) {
      26          60 :   if( FD_UNLIKELY( !admin ) ) FD_LOG_CRIT(( "NULL ljoin" ));
      27             : 
      28          60 :   if( FD_UNLIKELY( !fd_funk_leave( admin->funk, opt_shfunk ) ) ) FD_LOG_CRIT(( "fd_funk_leave failed" ));
      29             : 
      30          60 :   return admin;
      31          60 : }
      32             : 
      33             : /* Begin transaction-level operations.  It is assumed that funk_txn data
      34             :    structures are not concurrently modified.  This includes txn_pool and
      35             :    txn_map. */
      36             : 
      37             : void
      38             : fd_accdb_attach_child( fd_accdb_admin_t *        db,
      39             :                        fd_funk_txn_xid_t const * xid_parent,
      40      571857 :                        fd_funk_txn_xid_t const * xid_new ) {
      41      571857 :   FD_LOG_INFO(( "accdb txn xid %lu:%lu: created with parent %lu:%lu",
      42      571857 :                 xid_new   ->ul[0], xid_new   ->ul[1],
      43      571857 :                 xid_parent->ul[0], xid_parent->ul[1] ));
      44      571857 :   fd_funk_txn_prepare( db->funk, xid_parent, xid_new );
      45      571857 : }
      46             : 
      47             : static void
      48             : fd_accdb_txn_cancel_one( fd_accdb_admin_t * admin,
      49      347094 :                          fd_funk_txn_t *    txn ) {
      50      347094 :   FD_LOG_INFO(( "accdb txn laddr=%p xid %lu:%lu: cancel", (void *)txn, txn->xid.ul[0], txn->xid.ul[1] ));
      51             : 
      52      347094 :   if( FD_UNLIKELY( txn->state!=FD_FUNK_TXN_STATE_ACTIVE ) ) {
      53           0 :     FD_LOG_CRIT(( "cannot cancel xid %lu:%lu: unxpected state %u-%s",
      54           0 :                   txn->xid.ul[0], txn->xid.ul[1],
      55           0 :                   txn->state, fd_funk_txn_state_str( txn->state ) ));
      56           0 :   }
      57      347094 :   fd_funk_t * funk = admin->funk;
      58      347094 :   if( FD_UNLIKELY( !fd_funk_txn_idx_is_null( txn->child_head_cidx ) ||
      59      347094 :                    !fd_funk_txn_idx_is_null( txn->child_tail_cidx ) ) ) {
      60           0 :     FD_LOG_CRIT(( "fd_accdb_txn_cancel failed: txn at %p with xid %lu:%lu has children (data corruption?)",
      61           0 :                   (void *)txn, txn->xid.ul[0], txn->xid.ul[1] ));
      62           0 :   }
      63             : 
      64             :   /* Phase 1: Drain users from transaction */
      65             : 
      66      347094 :   fd_rwlock_write( txn->lock );
      67      347094 :   FD_COMPILER_MFENCE();
      68      347094 :   FD_VOLATILE( txn->state ) = FD_FUNK_TXN_STATE_CANCEL;
      69             : 
      70             :   /* Phase 2: Detach all records */
      71             : 
      72      347094 :   FD_COMPILER_MFENCE();
      73      347094 :   uint const rec_head_idx = txn->rec_head_idx;
      74      347094 :   txn->rec_head_idx = FD_FUNK_REC_IDX_NULL;
      75      347094 :   txn->rec_tail_idx = FD_FUNK_REC_IDX_NULL;
      76      347094 :   FD_COMPILER_MFENCE();
      77             : 
      78             :   /* Phase 3: Remove records */
      79             : 
      80      347094 :   ulong rec_cnt = 0UL;
      81      347094 :   uint rec_idx = rec_head_idx;
      82     1030707 :   while( !fd_funk_rec_idx_is_null( rec_idx ) ) {
      83      683613 :     fd_funk_rec_t * rec = &funk->rec_pool->ele[ rec_idx ];
      84      683613 :     fd_funk_xid_key_pair_t pair = FD_VOLATILE_CONST( rec->pair );
      85             : 
      86      683613 :     uint next_idx = rec->next_idx;
      87      683613 :     if( FD_UNLIKELY( !fd_funk_txn_xid_eq( pair.xid, &txn->xid ) ) ) {
      88           0 :       FD_LOG_CRIT(( "Record does not belong to txn being cancelled (data corruption?): rec_idx=%u", rec_idx ));
      89           0 :     }
      90             : 
      91             :     /* Phase 3.1: Hide record */
      92             : 
      93      683613 :     fd_funk_rec_query_t query[1];
      94      683613 :     int remove_err = fd_funk_rec_map_remove( funk->rec_map, &pair, NULL, query, FD_MAP_FLAG_BLOCKING );
      95      683613 :     if( FD_UNLIKELY( remove_err ) ) FD_LOG_CRIT(( "fd_funk_rec_map_remove failed: %i-%s", remove_err, fd_map_strerror( remove_err ) ));
      96      683613 :     if( FD_UNLIKELY( query->ele!=rec ) ) FD_LOG_CRIT(( "Found duplicate record in map idx[0]=%p idx[1]=%p", (void *)query->ele, (void *)rec ));
      97             : 
      98             :     /* Phase 3.2: Mark record as invalid */
      99             : 
     100      683613 :     FD_COMPILER_MFENCE();
     101      683613 :     memset( &rec->pair, 0, sizeof(fd_funk_xid_key_pair_t) );
     102      683613 :     FD_COMPILER_MFENCE();
     103             : 
     104             :     /* Phase 3.3: Free record */
     105             : 
     106      683613 :     fd_funk_val_flush( rec, funk->alloc, funk->wksp );
     107      683613 :     rec->next_idx = FD_FUNK_REC_IDX_NULL;
     108      683613 :     rec->prev_idx = FD_FUNK_REC_IDX_NULL;
     109      683613 :     fd_funk_rec_pool_release( funk->rec_pool, rec, 1 );
     110      683613 :     rec_idx = next_idx;
     111      683613 :     rec_cnt++;
     112      683613 :   }
     113      347094 :   admin->metrics.revert_cnt += rec_cnt;
     114      347094 :   FD_LOG_INFO(( "accdb freed %lu records while cancelling txn %lu:%lu",
     115      347094 :                 rec_cnt, txn->xid.ul[0], txn->xid.ul[1] ));
     116             : 
     117             :   /* Phase 4: Remove transaction from fork graph */
     118             : 
     119      347094 :   uint self_cidx = fd_funk_txn_cidx( (ulong)( txn-funk->txn_pool->ele ) );
     120      347094 :   uint prev_cidx = txn->sibling_prev_cidx; ulong prev_idx = fd_funk_txn_idx( prev_cidx );
     121      347094 :   uint next_cidx = txn->sibling_next_cidx; ulong next_idx = fd_funk_txn_idx( next_cidx );
     122      347094 :   if( !fd_funk_txn_idx_is_null( next_idx ) ) {
     123      156813 :     funk->txn_pool->ele[ next_idx ].sibling_prev_cidx = prev_cidx;
     124      156813 :   }
     125      347094 :   if( !fd_funk_txn_idx_is_null( prev_idx ) ) {
     126      109587 :     funk->txn_pool->ele[ prev_idx ].sibling_next_cidx = next_cidx;
     127      109587 :   }
     128      347094 :   if( !fd_funk_txn_idx_is_null( fd_funk_txn_idx( txn->parent_cidx ) ) ) {
     129      169809 :     fd_funk_txn_t * parent = &funk->txn_pool->ele[ fd_funk_txn_idx( txn->parent_cidx ) ];
     130      169809 :     if( parent->child_head_cidx==self_cidx ) parent->child_head_cidx = next_cidx;
     131      169809 :     if( parent->child_tail_cidx==self_cidx ) parent->child_tail_cidx = prev_cidx;
     132      177285 :   } else {
     133      177285 :     if( funk->shmem->child_head_cidx==self_cidx ) funk->shmem->child_head_cidx = next_cidx;
     134      177285 :     if( funk->shmem->child_tail_cidx==self_cidx ) funk->shmem->child_tail_cidx = prev_cidx;
     135      177285 :   }
     136             : 
     137             :   /* Phase 5: Remove transcation from index */
     138             : 
     139      347094 :   fd_funk_txn_map_query_t query[1];
     140      347094 :   int remove_err = fd_funk_txn_map_remove( funk->txn_map, &txn->xid, NULL, query, FD_MAP_FLAG_BLOCKING );
     141      347094 :   if( FD_UNLIKELY( remove_err!=FD_MAP_SUCCESS ) ) {
     142           0 :     FD_LOG_CRIT(( "fd_accdb_txn_cancel failed: fd_funk_txn_map_remove(%lu:%lu) failed: %i-%s",
     143           0 :                   txn->xid.ul[0], txn->xid.ul[1], remove_err, fd_map_strerror( remove_err ) ));
     144           0 :   }
     145             : 
     146             :   /* Phase 6: Free transaction object */
     147             : 
     148      347094 :   txn->parent_cidx       = UINT_MAX;
     149      347094 :   txn->sibling_prev_cidx = UINT_MAX;
     150      347094 :   txn->sibling_next_cidx = UINT_MAX;
     151      347094 :   fd_rwlock_unwrite( txn->lock );
     152      347094 :   FD_VOLATILE( txn->state ) = FD_FUNK_TXN_STATE_FREE;
     153      347094 :   fd_funk_txn_pool_release( funk->txn_pool, txn, 1 );
     154      347094 : }
     155             : 
     156             : /* Cancels txn and all children */
     157             : 
     158             : static void
     159             : fd_accdb_txn_cancel_tree( fd_accdb_admin_t * accdb,
     160      347094 :                           fd_funk_txn_t *    txn ) {
     161      516891 :   for(;;) {
     162      516891 :     ulong child_idx = fd_funk_txn_idx( txn->child_head_cidx );
     163      516891 :     if( fd_funk_txn_idx_is_null( child_idx ) ) break;
     164      169797 :     fd_funk_txn_t * child = &accdb->funk->txn_pool->ele[ child_idx ];
     165      169797 :     fd_accdb_txn_cancel_tree( accdb, child );
     166      169797 :   }
     167      347094 :   fd_accdb_txn_cancel_one( accdb, txn );
     168      347094 : }
     169             : 
     170             : /* Cancels all left/right siblings */
     171             : 
     172             : static void
     173             : fd_accdb_txn_cancel_prev_list( fd_accdb_admin_t * accdb,
     174      224739 :                                fd_funk_txn_t *    txn ) {
     175      224739 :   ulong self_idx = (ulong)( txn - accdb->funk->txn_pool->ele );
     176      313806 :   for(;;) {
     177      313806 :     ulong prev_idx = fd_funk_txn_idx( txn->sibling_prev_cidx );
     178      313806 :     if( FD_UNLIKELY( prev_idx==self_idx ) ) FD_LOG_CRIT(( "detected cycle in fork graph" ));
     179      313806 :     if( fd_funk_txn_idx_is_null( prev_idx ) ) break;
     180       89067 :     fd_funk_txn_t * sibling = &accdb->funk->txn_pool->ele[ prev_idx ];
     181       89067 :     fd_accdb_txn_cancel_tree( accdb, sibling );
     182       89067 :   }
     183      224739 : }
     184             : 
     185             : static void
     186             : fd_accdb_txn_cancel_next_list( fd_accdb_admin_t * accdb,
     187      224781 :                                fd_funk_txn_t *    txn ) {
     188      224781 :   ulong self_idx = (ulong)( txn - accdb->funk->txn_pool->ele );
     189      312969 :   for(;;) {
     190      312969 :     ulong next_idx = fd_funk_txn_idx( txn->sibling_next_cidx );
     191      312969 :     if( FD_UNLIKELY( next_idx==self_idx ) ) FD_LOG_CRIT(( "detected cycle in fork graph" ));
     192      312969 :     if( fd_funk_txn_idx_is_null( next_idx ) ) break;
     193       88188 :     fd_funk_txn_t * sibling = &accdb->funk->txn_pool->ele[ next_idx ];
     194       88188 :     fd_accdb_txn_cancel_tree( accdb, sibling );
     195       88188 :   }
     196      224781 : }
     197             : 
     198             : void
     199             : fd_accdb_cancel( fd_accdb_admin_t *        accdb,
     200          42 :                  fd_funk_txn_xid_t const * xid ) {
     201          42 :   fd_funk_t * funk = accdb->funk;
     202             : 
     203          42 :   fd_funk_txn_t * txn = fd_funk_txn_query( xid, funk->txn_map );
     204          42 :   if( FD_UNLIKELY( !txn ) ) {
     205           0 :     FD_LOG_CRIT(( "fd_accdb_txn_cancel failed: txn with xid %lu:%lu not found", xid->ul[0], xid->ul[1] ));
     206           0 :   }
     207             : 
     208          42 :   fd_accdb_txn_cancel_next_list( accdb, txn );
     209          42 :   fd_accdb_txn_cancel_tree( accdb, txn );
     210          42 : }
     211             : 
     212             : /* fd_accdb_chain_gc_root cleans up a stale "rooted" version of a
     213             :    record. */
     214             : 
     215             : static void
     216             : fd_accdb_chain_gc_root( fd_accdb_admin_t *             accdb,
     217      593448 :                         fd_funk_xid_key_pair_t const * pair ) {
     218      593448 :   fd_funk_t * funk = accdb->funk;
     219             : 
     220             :   /* Phase 1: Remove record from map if found */
     221             : 
     222      593448 :   fd_funk_rec_query_t query[1];
     223      593448 :   int rm_err = fd_funk_rec_map_remove( funk->rec_map, pair, NULL, query, FD_MAP_FLAG_BLOCKING );
     224      593448 :   if( rm_err==FD_MAP_ERR_KEY ) return;
     225      593220 :   if( FD_UNLIKELY( rm_err!=FD_MAP_SUCCESS ) ) FD_LOG_CRIT(( "fd_funk_rec_map_remove failed: %i-%s", rm_err, fd_map_strerror( rm_err ) ));
     226             : 
     227             :   /* Phase 2: Invalidate record */
     228             : 
     229      593220 :   fd_funk_rec_t * old_rec = query->ele;
     230      593220 :   memset( &old_rec->pair, 0, sizeof(fd_funk_xid_key_pair_t) );
     231      593220 :   FD_COMPILER_MFENCE();
     232             : 
     233             :   /* Phase 3: Free record */
     234             : 
     235      593220 :   old_rec->map_next = FD_FUNK_REC_IDX_NULL;
     236      593220 :   fd_funk_val_flush( old_rec, funk->alloc, funk->wksp );
     237      593220 :   fd_funk_rec_pool_release( funk->rec_pool, old_rec, 1 );
     238      593220 :   accdb->metrics.gc_root_cnt++;
     239      593220 : }
     240             : 
     241             : /* fd_accdb_publish_recs moves all records in a transaction to the DB
     242             :    root.  Currently, the DB root is stored by funk, which might change
     243             :    in the future.
     244             : 
     245             :    It is assumed at this point that the txn has no more concurrent
     246             :    users. */
     247             : 
     248             : static void
     249             : fd_accdb_publish_recs( fd_accdb_admin_t * accdb,
     250      224739 :                        fd_funk_txn_t *    txn ) {
     251             :   /* Iterate record list */
     252      224739 :   uint head = txn->rec_head_idx;
     253      224739 :   txn->rec_head_idx = FD_FUNK_REC_IDX_NULL;
     254      224739 :   txn->rec_tail_idx = FD_FUNK_REC_IDX_NULL;
     255      818187 :   while( !fd_funk_rec_idx_is_null( head ) ) {
     256      593448 :     fd_funk_rec_t * rec = &accdb->funk->rec_pool->ele[ head ];
     257             : 
     258             :     /* Evict previous value from hash chain */
     259      593448 :     fd_funk_xid_key_pair_t pair[1];
     260      593448 :     fd_funk_rec_key_copy( pair->key, rec->pair.key );
     261      593448 :     fd_funk_txn_xid_set_root( pair->xid );
     262      593448 :     fd_accdb_chain_gc_root( accdb, pair );
     263             : 
     264             :     /* Migrate record to root */
     265      593448 :     uint next = rec->next_idx;
     266      593448 :     rec->prev_idx = FD_FUNK_REC_IDX_NULL;
     267      593448 :     rec->next_idx = FD_FUNK_REC_IDX_NULL;
     268      593448 :     fd_funk_txn_xid_t const root = { .ul = { ULONG_MAX, ULONG_MAX } };
     269      593448 :     fd_funk_txn_xid_st_atomic( rec->pair.xid, &root );
     270      593448 :     accdb->metrics.root_cnt++;
     271             : 
     272      593448 :     head = next; /* next record */
     273      593448 :   }
     274      224739 : }
     275             : 
     276             : /* fd_accdb_txn_publish_one merges an in-prep transaction whose
     277             :    parent is the last published, into the parent. */
     278             : 
     279             : static void
     280             : fd_accdb_txn_publish_one( fd_accdb_admin_t * accdb,
     281      224739 :                           fd_funk_txn_t *    txn ) {
     282      224739 :   fd_funk_t * funk = accdb->funk;
     283             : 
     284             :   /* Phase 1: Mark transaction as "last published" */
     285             : 
     286      224739 :   fd_funk_txn_xid_t xid[1]; fd_funk_txn_xid_copy( xid, fd_funk_txn_xid( txn ) );
     287      224739 :   if( FD_UNLIKELY( !fd_funk_txn_idx_is_null( fd_funk_txn_idx( txn->parent_cidx ) ) ) ) {
     288           0 :     FD_LOG_CRIT(( "fd_accdb_publish failed: txn with xid %lu:%lu is not a child of the last published txn", xid->ul[0], xid->ul[1] ));
     289           0 :   }
     290      224739 :   fd_funk_txn_xid_st_atomic( funk->shmem->last_publish, xid );
     291      224739 :   FD_LOG_INFO(( "accdb txn laddr=%p xid %lu:%lu: publish", (void *)txn, txn->xid.ul[0], txn->xid.ul[1] ));
     292             : 
     293             :   /* Phase 2: Drain users from transaction */
     294             : 
     295      224739 :   fd_rwlock_write( txn->lock );
     296      224739 :   FD_VOLATILE( txn->state ) = FD_FUNK_TXN_STATE_PUBLISH;
     297             : 
     298             :   /* Phase 3: Migrate records */
     299             : 
     300      224739 :   fd_accdb_publish_recs( accdb, txn );
     301             : 
     302             :   /* Phase 4: Remove transaction from fork graph
     303             : 
     304             :      Because the transaction has no more records, removing it from the
     305             :      fork graph has no visible side effects to concurrent query ops
     306             :      (always return "no found") or insert ops (refuse to write to a
     307             :      "publish" state txn). */
     308             : 
     309      224739 :   { /* Adjust the parent pointers of the children to point to "last published" */
     310      224739 :     ulong child_idx = fd_funk_txn_idx( txn->child_head_cidx );
     311      372294 :     while( FD_UNLIKELY( !fd_funk_txn_idx_is_null( child_idx ) ) ) {
     312      147555 :       funk->txn_pool->ele[ child_idx ].parent_cidx = fd_funk_txn_cidx( FD_FUNK_TXN_IDX_NULL );
     313      147555 :       child_idx = fd_funk_txn_idx( funk->txn_pool->ele[ child_idx ].sibling_next_cidx );
     314      147555 :     }
     315      224739 :   }
     316             : 
     317             :   /* Phase 5: Remove transaction from index
     318             : 
     319             :      The transaction is now an orphan and won't get any new records. */
     320             : 
     321      224739 :   fd_funk_txn_map_query_t query[1];
     322      224739 :   int remove_err = fd_funk_txn_map_remove( funk->txn_map, xid, NULL, query, 0 );
     323      224739 :   if( FD_UNLIKELY( remove_err!=FD_MAP_SUCCESS ) ) {
     324           0 :     FD_LOG_CRIT(( "fd_accdb_publish failed: fd_funk_txn_map_remove failed: %i-%s", remove_err, fd_map_strerror( remove_err ) ));
     325           0 :   }
     326             : 
     327             :   /* Phase 6: Free transaction object */
     328             : 
     329      224739 :   fd_rwlock_unwrite( txn->lock );
     330      224739 :   FD_VOLATILE( txn->state ) = FD_FUNK_TXN_STATE_FREE;
     331      224739 :   txn->parent_cidx       = UINT_MAX;
     332      224739 :   txn->sibling_prev_cidx = UINT_MAX;
     333      224739 :   txn->sibling_next_cidx = UINT_MAX;
     334      224739 :   txn->child_head_cidx   = UINT_MAX;
     335      224739 :   txn->child_tail_cidx   = UINT_MAX;
     336      224739 :   fd_funk_txn_pool_release( funk->txn_pool, txn, 1 );
     337      224739 : }
     338             : 
     339             : void
     340             : fd_accdb_advance_root( fd_accdb_admin_t *        accdb,
     341      224739 :                        fd_funk_txn_xid_t const * xid ) {
     342      224739 :   fd_funk_t * funk = accdb->funk;
     343             : 
     344      224739 :   fd_funk_txn_t * txn = fd_funk_txn_query( xid, funk->txn_map );
     345      224739 :   if( FD_UNLIKELY( !txn ) ) {
     346           0 :     FD_LOG_CRIT(( "fd_accdb_txn_advance_root failed: txn with xid %lu:%lu not found", xid->ul[0], xid->ul[1] ));
     347           0 :   }
     348             : 
     349      224739 :   if( FD_UNLIKELY( !fd_funk_txn_idx_is_null( fd_funk_txn_idx( txn->parent_cidx ) ) ) ) {
     350           0 :     FD_LOG_CRIT(( "fd_accdb_txn_advance_root: parent of txn %lu:%lu is not root", xid->ul[0], xid->ul[1] ));
     351           0 :   }
     352             : 
     353      224739 :   FD_LOG_INFO(( "accdb txn laddr=%p xid %lu:%lu: advancing root",
     354      224739 :                 (void *)txn,
     355      224739 :                 xid->ul[0], xid->ul[1] ));
     356             : 
     357      224739 :   fd_accdb_txn_cancel_prev_list( accdb, txn );
     358      224739 :   fd_accdb_txn_cancel_next_list( accdb, txn );
     359      224739 :   txn->sibling_prev_cidx = UINT_MAX;
     360      224739 :   txn->sibling_next_cidx = UINT_MAX;
     361             : 
     362             :   /* Children of transaction are now children of root */
     363      224739 :   funk->shmem->child_head_cidx = txn->child_head_cidx;
     364      224739 :   funk->shmem->child_tail_cidx = txn->child_tail_cidx;
     365             : 
     366      224739 :   fd_accdb_txn_publish_one( accdb, txn );
     367      224739 : }
     368             : 
     369             : /* reset_rec_map frees all records in a funk instance. */
     370             : 
     371             : static void
     372          15 : reset_rec_map( fd_funk_t * funk ) {
     373          15 :   fd_wksp_t *          wksp     = funk->wksp;
     374          15 :   fd_alloc_t *         alloc    = funk->alloc;
     375          15 :   fd_funk_rec_map_t *  rec_map  = funk->rec_map;
     376          15 :   fd_funk_rec_pool_t * rec_pool = funk->rec_pool;
     377             : 
     378          15 :   ulong chain_cnt = fd_funk_rec_map_chain_cnt( rec_map );
     379         975 :   for( ulong chain_idx=0UL; chain_idx<chain_cnt; chain_idx++ ) {
     380         960 :     for(
     381         960 :         fd_funk_rec_map_iter_t iter = fd_funk_rec_map_iter( rec_map, chain_idx );
     382        1203 :         !fd_funk_rec_map_iter_done( iter );
     383         960 :     ) {
     384         243 :       fd_funk_rec_t * rec = fd_funk_rec_map_iter_ele( iter );
     385         243 :       ulong next = fd_funk_rec_map_private_idx( rec->map_next );;
     386             : 
     387             :       /* Remove rec object from map */
     388         243 :       fd_funk_rec_map_query_t rec_query[1];
     389         243 :       int err = fd_funk_rec_map_remove( rec_map, fd_funk_rec_pair( rec ), NULL, rec_query, FD_MAP_FLAG_BLOCKING );
     390         243 :       fd_funk_rec_key_t key; fd_funk_rec_key_copy( &key, rec->pair.key );
     391         243 :       if( FD_UNLIKELY( err!=FD_MAP_SUCCESS ) ) FD_LOG_CRIT(( "fd_funk_rec_map_remove failed (%i-%s)", err, fd_map_strerror( err ) ));
     392             : 
     393             :       /* Free rec resources */
     394         243 :       rec->map_next = FD_FUNK_REC_IDX_NULL;
     395         243 :       rec->next_idx = FD_FUNK_REC_IDX_NULL;
     396         243 :       rec->prev_idx = FD_FUNK_REC_IDX_NULL;
     397         243 :       memset( &rec->pair, 0, sizeof(fd_funk_xid_key_pair_t) );
     398         243 :       fd_funk_val_flush( rec, alloc, wksp );
     399         243 :       fd_funk_rec_pool_release( rec_pool, rec, 1 );
     400         243 :       iter.ele_idx = next;
     401         243 :     }
     402         960 :   }
     403          15 : }
     404             : 
     405             : /* clear_txn_list does a depth-first traversal of the txn tree.
     406             :    Removes all txns. */
     407             : 
     408             : static void
     409             : clear_txn_list( fd_funk_t * funk,
     410          27 :                 ulong       txn_head_idx ) {
     411          27 :   fd_funk_txn_pool_t * txn_pool = funk->txn_pool;
     412          27 :   fd_funk_txn_map_t *  txn_map  = funk->txn_map;
     413          27 :   for( ulong idx = txn_head_idx;
     414          39 :        !fd_funk_txn_idx_is_null( idx );
     415          27 :   ) {
     416          12 :     fd_funk_txn_t * txn = &txn_pool->ele[ idx ];
     417          12 :     fd_funk_txn_state_assert( txn, FD_FUNK_TXN_STATE_ACTIVE );
     418          12 :     ulong next_idx  = fd_funk_txn_idx( txn->sibling_next_cidx );
     419          12 :     ulong child_idx = fd_funk_txn_idx( txn->child_head_cidx );
     420          12 :     txn->rec_head_idx      = FD_FUNK_REC_IDX_NULL;
     421          12 :     txn->rec_tail_idx      = FD_FUNK_REC_IDX_NULL;
     422          12 :     txn->child_head_cidx   = UINT_MAX;
     423          12 :     txn->child_tail_cidx   = UINT_MAX;
     424          12 :     txn->parent_cidx       = UINT_MAX;
     425          12 :     txn->sibling_prev_cidx = UINT_MAX;
     426          12 :     txn->sibling_next_cidx = UINT_MAX;
     427          12 :     clear_txn_list( funk, child_idx );
     428          12 :     fd_funk_txn_map_query_t query[1];
     429          12 :     int rm_err = fd_funk_txn_map_remove( txn_map, &txn->xid, NULL, query, FD_MAP_FLAG_BLOCKING );
     430          12 :     if( FD_UNLIKELY( rm_err!=FD_MAP_SUCCESS ) ) FD_LOG_CRIT(( "fd_funk_txn_map_remove failed (%i-%s)", rm_err, fd_map_strerror( rm_err ) ));
     431          12 :     txn->state = FD_FUNK_TXN_STATE_FREE;
     432          12 :     int free_err = fd_funk_txn_pool_release( txn_pool, txn, 1 );
     433          12 :     if( FD_UNLIKELY( free_err!=FD_POOL_SUCCESS ) ) FD_LOG_CRIT(( "fd_funk_txn_pool_release failed (%i)", free_err ));
     434          12 :     idx = next_idx;
     435          12 :   }
     436          27 :   funk->shmem->child_head_cidx = UINT_MAX;
     437          27 :   funk->shmem->child_tail_cidx = UINT_MAX;
     438          27 : }
     439             : 
     440             : void
     441          15 : fd_accdb_clear( fd_accdb_admin_t * cache ) {
     442          15 :   fd_funk_t * funk = cache->funk;
     443          15 :   clear_txn_list( funk, fd_funk_txn_idx( funk->shmem->child_head_cidx ) );
     444          15 :   reset_rec_map( funk );
     445          15 : }
     446             : 
     447             : void
     448         198 : fd_accdb_verify( fd_accdb_admin_t * admin ) {
     449         198 :   FD_TEST( fd_funk_verify( admin->funk )==FD_FUNK_SUCCESS );
     450         198 : }

Generated by: LCOV version 1.14