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