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 : }