LCOV - code coverage report
Current view: top level - flamenco/accdb - fd_accdb_lineage.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 68 97 70.1 %
Date: 2026-03-19 18:19:27 Functions: 2 2 100.0 %

          Line data    Source code
       1             : #include "fd_accdb_lineage.h"
       2             : #include "../../funk/fd_funk.h"
       3             : 
       4             : void
       5             : fd_accdb_lineage_set_fork_slow( fd_accdb_lineage_t *      lineage,
       6             :                                 fd_funk_t const *         funk,
       7        3533 :                                 fd_funk_txn_xid_t const * xid ) {
       8        3533 :   fd_funk_txn_xid_t next_xid = *xid;
       9        3533 :   fd_funk_txn_t *   tip      = NULL;
      10             : 
      11             :   /* Walk transaction graph, recovering from overruns on-the-fly */
      12        3533 :   lineage->fork_depth = 0UL;
      13             : 
      14        3533 :   ulong txn_max = fd_funk_txn_pool_ele_max( funk->txn_pool );
      15        3533 :   ulong i;
      16        3832 :   for( i=0UL; i<lineage->max_depth; i++ ) {
      17        3832 :     fd_funk_txn_map_query_t query[1];
      18        3832 :     fd_funk_txn_t *         candidate;
      19        3832 :     fd_funk_txn_xid_t       found_xid;
      20        3832 :     ulong                   parent_idx;
      21        3832 :     fd_funk_txn_xid_t       parent_xid;
      22        3832 : retry:
      23             :     /* Speculatively look up transaction from map */
      24        3832 :     for(;;) {
      25        3832 :       int query_err = fd_funk_txn_map_query_try( funk->txn_map, &next_xid, NULL, query, 0 );
      26        3832 :       if( FD_UNLIKELY( query_err==FD_MAP_ERR_AGAIN ) ) {
      27             :         /* FIXME random backoff */
      28           0 :         FD_SPIN_PAUSE();
      29           0 :         continue;
      30           0 :       }
      31        3832 :       if( query_err==FD_MAP_ERR_KEY ) goto done;
      32        3832 :       if( FD_UNLIKELY( query_err!=FD_MAP_SUCCESS ) ) {
      33           0 :         FD_LOG_CRIT(( "fd_funk_txn_map_query_try failed: %i-%s", query_err, fd_map_strerror( query_err ) ));
      34           0 :       }
      35        3832 :       break;
      36        3832 :     }
      37             : 
      38             :     /* Lookup parent transaction while recovering from overruns
      39             :        FIXME This would be a lot easier if transactions specified
      40             :              parent by XID instead of by pointer ... */
      41        3832 :     candidate = fd_funk_txn_map_query_ele( query );
      42        3832 :     FD_COMPILER_MFENCE();
      43        3832 :     do {
      44        3832 :       found_xid  = FD_VOLATILE_CONST( candidate->xid );
      45        3832 :       parent_idx = fd_funk_txn_idx( FD_VOLATILE_CONST( candidate->parent_cidx ) );
      46        3832 :       if( fd_funk_txn_idx_is_null( parent_idx ) ) break;
      47         299 :       if( FD_UNLIKELY( parent_idx>=txn_max ) ) FD_LOG_CRIT(( "corrupt txn parent idx %lu", parent_idx ));
      48             : 
      49         299 :       FD_COMPILER_MFENCE();
      50         299 :       fd_funk_txn_t const * parent = &funk->txn_pool->ele[ parent_idx ];
      51         299 :       parent_xid = FD_VOLATILE_CONST( parent->xid );
      52         299 :       FD_COMPILER_MFENCE();
      53             : 
      54         299 :       parent_idx = fd_funk_txn_idx( FD_VOLATILE_CONST( candidate->parent_cidx ) );
      55         299 :       if( fd_funk_txn_idx_is_null( parent_idx ) ) break;
      56         299 :       if( FD_UNLIKELY( parent_idx>=txn_max ) ) FD_LOG_CRIT(( "corrupt txn parent idx %lu", parent_idx ));
      57         299 :     } while(0);
      58        3832 :     FD_COMPILER_MFENCE();
      59             : 
      60        3832 :     ulong candidate_idx = (ulong)( candidate - funk->txn_pool->ele );
      61        3832 :     fd_rwlock_read( &funk->txn_lock[ candidate_idx ] );
      62             : 
      63             :     /* Verify speculative loads by ensuring txn still exists in map */
      64        3832 :     if( FD_UNLIKELY( fd_funk_txn_map_query_test( query )!=FD_MAP_SUCCESS ) ) {
      65           0 :       fd_rwlock_unread( &funk->txn_lock[ candidate_idx ] );
      66           0 :       FD_SPIN_PAUSE();
      67           0 :       goto retry;
      68           0 :     }
      69             : 
      70        3832 :     if( FD_UNLIKELY( !fd_funk_txn_xid_eq( &found_xid, &next_xid ) ) ) {
      71           0 :       FD_LOG_CRIT(( "fd_accdb_load_fork_slow detected memory corruption: expected xid %lu:%lu at %p, found %lu:%lu",
      72           0 :                     next_xid.ul[0], next_xid.ul[1],
      73           0 :                     (void *)candidate,
      74           0 :                     found_xid.ul[0], found_xid.ul[1] ));
      75           0 :     }
      76             : 
      77        3832 :     if( !tip ) tip = candidate;  /* remember head of fork */
      78         299 :     else       fd_rwlock_unread( &funk->txn_lock[ candidate_idx ] );
      79        3832 :     lineage->fork   [ i ] = next_xid;
      80        3832 :     lineage->txn_idx[ i ] = (uint)( candidate - funk->txn_pool->ele );
      81        3832 :     if( fd_funk_txn_idx_is_null( parent_idx ) ) {
      82             :       /* Reached root */
      83        3533 :       i++;
      84        3533 :       break;
      85        3533 :     }
      86         299 :     next_xid = parent_xid;
      87         299 :   }
      88             : 
      89        3533 : done:
      90        3533 :   lineage->fork_depth = i;
      91        3533 :   if( FD_UNLIKELY( lineage->fork_depth==lineage->max_depth ) ) {
      92           0 :     FD_LOG_CRIT(( "Account database fork depth exceeded max of %lu", lineage->max_depth ));
      93           0 :   }
      94             : 
      95             :   /* Remember head of fork */
      96        3533 :   if( tip ) {
      97        3533 :     lineage->tip_txn_idx = (ulong)( tip - funk->txn_pool->ele );
      98        3533 :     fd_rwlock_unread( &funk->txn_lock[ lineage->tip_txn_idx ] );
      99        3533 :   } else {
     100           0 :     lineage->tip_txn_idx = ULONG_MAX;  /* XID is rooted */
     101           0 :   }
     102        3533 : }
     103             : 
     104             : fd_funk_txn_t *
     105             : fd_accdb_lineage_write_check( fd_accdb_lineage_t const * lineage,
     106      128817 :                               fd_funk_t const *          funk ) {
     107      128817 :   ulong txn_idx = lineage->tip_txn_idx;
     108      128817 :   fd_funk_txn_xid_t const * xid = &lineage->fork[ 0 ];
     109      128817 :   if( FD_UNLIKELY( txn_idx==ULONG_MAX ) ) {
     110           0 :     FD_LOG_CRIT(( "write failed: XID %lu:%lu is rooted", xid->ul[0], xid->ul[1] ));
     111           0 :   }
     112      128817 :   if( FD_UNLIKELY( txn_idx >= fd_funk_txn_pool_ele_max( funk->txn_pool ) ) ) {
     113           0 :     FD_LOG_CRIT(( "memory corruption detected: invalid txn_idx %lu (max %lu)",
     114           0 :                   txn_idx, fd_funk_txn_pool_ele_max( funk->txn_pool ) ));
     115           0 :   }
     116      128817 :   fd_funk_txn_t * txn = &funk->txn_pool->ele[ txn_idx ];
     117      128817 :   if( FD_UNLIKELY( !fd_funk_txn_xid_eq( &txn->xid, xid ) ) ) {
     118           0 :     FD_LOG_CRIT(( "Failed to modify account: data race detected on fork node (expected XID %lu:%lu, found %lu:%lu)",
     119           0 :                   xid->ul[0],     xid->ul[1],
     120           0 :                   txn->xid.ul[0], txn->xid.ul[1] ));
     121           0 :   }
     122      128817 :   if( FD_UNLIKELY( fd_funk_txn_is_frozen( txn ) ) ) {
     123           0 :     FD_LOG_CRIT(( "Failed to modify account: XID %lu:%lu has children/is frozen", xid->ul[0], xid->ul[1] ));
     124           0 :   }
     125      128817 :   return txn;
     126      128817 : }

Generated by: LCOV version 1.14