|
| 1 | +#include "fd_accdb_impl_v2.h" |
| 2 | +#include "fd_vinyl_req_pool.h" |
| 3 | + |
| 4 | +FD_STATIC_ASSERT( alignof(fd_accdb_user_v2_t)<=alignof(fd_accdb_user_t), layout ); |
| 5 | +FD_STATIC_ASSERT( sizeof (fd_accdb_user_v2_t)<=sizeof(fd_accdb_user_t), layout ); |
| 6 | + |
| 7 | +fd_accdb_peek_t * |
| 8 | +fd_accdb_peek_funk( fd_accdb_user_v1_t * accdb, |
| 9 | + fd_accdb_peek_t * peek, |
| 10 | + fd_funk_txn_xid_t const * xid, |
| 11 | + void const * address ); |
| 12 | + |
| 13 | +void |
| 14 | +fd_accdb_load_fork_slow( fd_accdb_user_v1_t * accdb, |
| 15 | + fd_funk_txn_xid_t const * xid ); |
| 16 | + |
| 17 | +static inline void |
| 18 | +fd_accdb_load_fork( fd_accdb_user_v1_t * accdb, |
| 19 | + fd_funk_txn_xid_t const * xid ) { |
| 20 | + /* Skip if already on the correct fork */ |
| 21 | + if( FD_LIKELY( (!!accdb->fork_depth) & (!!fd_funk_txn_xid_eq( &accdb->fork[ 0 ], xid ) ) ) ) return; |
| 22 | + if( FD_UNLIKELY( accdb->base.rw_active ) ) { |
| 23 | + FD_LOG_CRIT(( "Invariant violation: all active account references of an accdb_user must be accessed through the same XID (active XID %lu:%lu, requested XID %lu:%lu)", |
| 24 | + accdb->fork[0].ul[0], accdb->fork[0].ul[1], |
| 25 | + xid ->ul[0], xid ->ul[1] )); |
| 26 | + } |
| 27 | + fd_accdb_load_fork_slow( accdb, xid ); /* switch fork */ |
| 28 | +} |
| 29 | + |
| 30 | +void |
| 31 | +fd_accdb_user_v2_fini( fd_accdb_user_t * accdb ) { |
| 32 | + fd_accdb_user_v2_t * user = (fd_accdb_user_v2_t *)accdb; |
| 33 | + |
| 34 | + fd_vinyl_rq_leave( user->vinyl_rq ); |
| 35 | + |
| 36 | + /* superclass destructor */ |
| 37 | + user->base.accdb_type = FD_ACCDB_TYPE_V1; |
| 38 | + fd_accdb_user_v1_fini( accdb ); |
| 39 | +} |
| 40 | + |
| 41 | +fd_accdb_peek_t * |
| 42 | +fd_accdb_user_v2_peek( fd_accdb_user_t * accdb, |
| 43 | + fd_accdb_peek_t * peek, |
| 44 | + fd_funk_txn_xid_t const * xid, |
| 45 | + void const * address ) { |
| 46 | + /* FIXME this should query vinyl cache too (via vinyl_meta/vinyl_data) */ |
| 47 | + return fd_accdb_user_v1_peek( accdb, peek, xid, address ); |
| 48 | +} |
| 49 | + |
| 50 | +void |
| 51 | +fd_accdb_user_v2_close_ro( fd_accdb_user_t * accdb_, |
| 52 | + fd_accdb_ro_t * ro ); |
| 53 | + |
| 54 | +fd_accdb_ro_t * |
| 55 | +fd_accdb_user_v2_open_ro( fd_accdb_user_t * accdb_, |
| 56 | + fd_accdb_ro_t * ro, |
| 57 | + fd_funk_txn_xid_t const * xid, |
| 58 | + void const * address ) { |
| 59 | + fd_accdb_user_v2_t * accdb = (fd_accdb_user_v2_t *)accdb_; |
| 60 | + fd_accdb_load_fork( &accdb->v1, xid ); |
| 61 | + |
| 62 | + /* Check whether value is present in funk overlay */ |
| 63 | + |
| 64 | + fd_accdb_peek_t peek[1]; |
| 65 | + if( fd_accdb_peek_funk( &accdb->v1, peek, xid, address ) ) { |
| 66 | + if( FD_UNLIKELY( !peek->acc->meta->lamports ) ) return NULL; |
| 67 | + accdb->base.ro_active++; |
| 68 | + *ro = *peek->acc; |
| 69 | + return ro; |
| 70 | + } |
| 71 | + |
| 72 | + /* Nothing found in funk, query vinyl */ |
| 73 | + /* FIXME potential here to do a pre-flight check against vinyl_meta to |
| 74 | + reduce the amount of requests we're sending to vinyl */ |
| 75 | + |
| 76 | + /* Send an ACQUIRE request */ |
| 77 | + |
| 78 | + ulong batch_idx = fd_vinyl_req_pool_acquire ( accdb->vinyl_req_pool ); |
| 79 | + fd_vinyl_key_t * req_key = fd_vinyl_req_batch_key ( accdb->vinyl_req_pool, batch_idx ); |
| 80 | + ulong * req_val_gaddr = fd_vinyl_req_batch_val_gaddr( accdb->vinyl_req_pool, batch_idx ); |
| 81 | + schar * req_err = fd_vinyl_req_batch_err ( accdb->vinyl_req_pool, batch_idx ); |
| 82 | + fd_vinyl_comp_t * comp = fd_vinyl_req_batch_comp ( accdb->vinyl_req_pool, batch_idx ); |
| 83 | + fd_vinyl_key_init( req_key, address, 32UL ); |
| 84 | + memset( comp, 0, sizeof(fd_vinyl_comp_t) ); |
| 85 | + fd_vinyl_req_send_batch( |
| 86 | + accdb->vinyl_rq, |
| 87 | + accdb->vinyl_req_pool, |
| 88 | + accdb->vinyl_req_id++, |
| 89 | + accdb->vinyl_link_id, |
| 90 | + FD_VINYL_REQ_TYPE_ACQUIRE, |
| 91 | + 0UL, /* flags */ |
| 92 | + batch_idx, |
| 93 | + 1UL, /* batch_cnt */ |
| 94 | + 0UL /* val_max */ |
| 95 | + ); |
| 96 | + |
| 97 | + /* Poll for completion */ |
| 98 | + |
| 99 | + while( FD_VOLATILE_CONST( comp->seq )!=1UL ) FD_SPIN_PAUSE(); |
| 100 | + FD_COMPILER_MFENCE(); |
| 101 | + int comp_err = FD_VOLATILE_CONST( comp->err ); |
| 102 | + if( FD_UNLIKELY( comp_err!=FD_VINYL_SUCCESS ) ) { |
| 103 | + FD_LOG_CRIT(( "vinyl tile rejected my ACQUIRE request: %i-%s", comp_err, fd_vinyl_strerror( comp_err ) )); |
| 104 | + } |
| 105 | + int err = FD_VOLATILE_CONST( req_err[0] ); |
| 106 | + if( err==FD_VINYL_ERR_KEY ) { /* not found */ |
| 107 | + fd_vinyl_req_pool_release( accdb->vinyl_req_pool, batch_idx ); |
| 108 | + return NULL; |
| 109 | + } |
| 110 | + if( FD_UNLIKELY( err!=FD_VINYL_SUCCESS ) ) { |
| 111 | + FD_LOG_CRIT(( "vinyl tile ACQUIRE request failed: %i-%s", err, fd_vinyl_strerror( err ) )); |
| 112 | + } |
| 113 | + |
| 114 | + /* Return result */ |
| 115 | + |
| 116 | + ulong val_gaddr = FD_VOLATILE_CONST( req_val_gaddr[0] ); |
| 117 | + fd_account_meta_t const * meta = fd_wksp_laddr_fast( accdb->vinyl_data_wksp, val_gaddr ); |
| 118 | + fd_vinyl_req_pool_release( accdb->vinyl_req_pool, batch_idx ); |
| 119 | + |
| 120 | + accdb->base.ro_active++; |
| 121 | + *ro = (fd_accdb_ro_t) { |
| 122 | + .meta = meta |
| 123 | + }; |
| 124 | + memcpy( ro->ref->address, address, 32UL ); |
| 125 | + |
| 126 | + /* Hide tombstones */ |
| 127 | + |
| 128 | + if( FD_UNLIKELY( !meta->lamports ) ) { |
| 129 | + fd_accdb_user_v2_close_ro( accdb_, ro ); |
| 130 | + return NULL; |
| 131 | + } |
| 132 | + |
| 133 | + return ro; |
| 134 | +} |
| 135 | + |
| 136 | +void |
| 137 | +fd_accdb_user_v2_close_ro( fd_accdb_user_t * accdb_, |
| 138 | + fd_accdb_ro_t * ro ) { |
| 139 | + fd_accdb_user_v2_t * accdb = (fd_accdb_user_v2_t *)accdb_; |
| 140 | + |
| 141 | + if( ro->rec ) { |
| 142 | + accdb->base.ro_active--; |
| 143 | + return; |
| 144 | + } |
| 145 | + |
| 146 | + /* Send a RELEASE request */ |
| 147 | + |
| 148 | + ulong batch_idx = fd_vinyl_req_pool_acquire ( accdb->vinyl_req_pool ); |
| 149 | + fd_vinyl_key_t * req_key = fd_vinyl_req_batch_key ( accdb->vinyl_req_pool, batch_idx ); |
| 150 | + ulong * req_val_gaddr = fd_vinyl_req_batch_val_gaddr( accdb->vinyl_req_pool, batch_idx ); |
| 151 | + schar * req_err = fd_vinyl_req_batch_err ( accdb->vinyl_req_pool, batch_idx ); |
| 152 | + fd_vinyl_comp_t * comp = fd_vinyl_req_batch_comp ( accdb->vinyl_req_pool, batch_idx ); |
| 153 | + fd_vinyl_key_init( req_key, ro->ref->address, 32UL ); |
| 154 | + req_val_gaddr[0] = fd_wksp_gaddr_fast( accdb->vinyl_data_wksp, (void *)ro->meta ); |
| 155 | + memset( comp, 0, sizeof(fd_vinyl_comp_t) ); |
| 156 | + fd_vinyl_req_send_batch( |
| 157 | + accdb->vinyl_rq, |
| 158 | + accdb->vinyl_req_pool, |
| 159 | + accdb->vinyl_req_id++, |
| 160 | + accdb->vinyl_link_id, |
| 161 | + FD_VINYL_REQ_TYPE_RELEASE, |
| 162 | + 0UL, /* flags */ |
| 163 | + batch_idx, |
| 164 | + 1UL, /* batch_cnt */ |
| 165 | + 0UL /* val_max */ |
| 166 | + ); |
| 167 | + |
| 168 | + /* Poll for completion */ |
| 169 | + |
| 170 | + while( FD_VOLATILE_CONST( comp->seq )!=1UL ) FD_SPIN_PAUSE(); |
| 171 | + FD_COMPILER_MFENCE(); |
| 172 | + int comp_err = FD_VOLATILE_CONST( comp->err ); |
| 173 | + if( FD_UNLIKELY( comp_err!=FD_VINYL_SUCCESS ) ) { |
| 174 | + FD_LOG_CRIT(( "vinyl tile rejected my RELEASE request: %i-%s", comp_err, fd_vinyl_strerror( comp_err ) )); |
| 175 | + } |
| 176 | + int err = FD_VOLATILE_CONST( req_err[0] ); |
| 177 | + if( FD_UNLIKELY( err!=FD_VINYL_SUCCESS ) ) { |
| 178 | + FD_LOG_CRIT(( "vinyl tile RELEASE request failed: %i-%s", err, fd_vinyl_strerror( err ) )); |
| 179 | + } |
| 180 | + fd_vinyl_req_pool_release( accdb->vinyl_req_pool, batch_idx ); |
| 181 | + |
| 182 | + accdb->base.ro_active--; |
| 183 | +} |
| 184 | + |
| 185 | +fd_accdb_rw_t * |
| 186 | +fd_accdb_user_v2_open_rw( fd_accdb_user_t * accdb, |
| 187 | + fd_accdb_rw_t * rw, |
| 188 | + fd_funk_txn_xid_t const * xid, |
| 189 | + void const * address, |
| 190 | + ulong data_max, |
| 191 | + int do_create ) { |
| 192 | + return fd_accdb_user_v1_open_rw( accdb, rw, xid, address, data_max, do_create ); |
| 193 | +} |
| 194 | + |
| 195 | +void |
| 196 | +fd_accdb_user_v2_close_rw( fd_accdb_user_t * accdb, |
| 197 | + fd_accdb_rw_t * write ) { |
| 198 | + fd_accdb_user_v1_close_rw( accdb, write ); |
| 199 | +} |
| 200 | + |
| 201 | +fd_accdb_user_vt_t const fd_accdb_user_v2_vt = { |
| 202 | + .fini = fd_accdb_user_v2_fini, |
| 203 | + .peek = fd_accdb_user_v2_peek, |
| 204 | + .open_ro = fd_accdb_user_v2_open_ro, |
| 205 | + .close_ro = fd_accdb_user_v2_close_ro, |
| 206 | + .open_rw = fd_accdb_user_v2_open_rw, |
| 207 | + .close_rw = fd_accdb_user_v2_close_rw |
| 208 | +}; |
| 209 | + |
| 210 | +fd_accdb_user_t * |
| 211 | +fd_accdb_user_v2_init( fd_accdb_user_t * accdb_, |
| 212 | + void * funk, |
| 213 | + void * vinyl_rq, |
| 214 | + void * vinyl_data, |
| 215 | + void * vinyl_req_pool, |
| 216 | + ulong vinyl_link_id ) { |
| 217 | + /* Call superclass constructor */ |
| 218 | + if( FD_UNLIKELY( !fd_accdb_user_v1_init( accdb_, funk ) ) ) { |
| 219 | + return NULL; |
| 220 | + } |
| 221 | + |
| 222 | + fd_vinyl_rq_t * rq = fd_vinyl_rq_join( vinyl_rq ); |
| 223 | + fd_vinyl_req_pool_t * req_pool = fd_vinyl_req_pool_join( vinyl_req_pool ); |
| 224 | + if( FD_UNLIKELY( !rq || !req_pool ) ) { |
| 225 | + /* component joins log warning if this is reached */ |
| 226 | + FD_LOG_WARNING(( "Failed to initialize database client" )); |
| 227 | + return NULL; |
| 228 | + } |
| 229 | + |
| 230 | + fd_accdb_user_v2_t * accdb = fd_type_pun( accdb_ ); |
| 231 | + accdb->vinyl_req_id = fd_vinyl_rq_seq( vinyl_rq ); |
| 232 | + accdb->vinyl_rq = rq; |
| 233 | + accdb->vinyl_link_id = vinyl_link_id; |
| 234 | + accdb->vinyl_data_wksp = vinyl_data; |
| 235 | + accdb->vinyl_req_pool = req_pool; |
| 236 | + accdb->base.accdb_type = FD_ACCDB_TYPE_V2; |
| 237 | + accdb->base.vt = &fd_accdb_user_v2_vt; |
| 238 | + return accdb_; |
| 239 | +} |
0 commit comments