Line data Source code
1 : #ifndef HEADER_fd_src_flamenco_accdb_fd_accdb_ref_h 2 : #define HEADER_fd_src_flamenco_accdb_fd_accdb_ref_h 3 : 4 : /* fd_accdb_ref.h provides account database handle classes. 5 : 6 : - accdb_ref is an opaque handle to an account database cache entry. 7 : - accdb_ro (extends accdb_ref) represents a read-only handle. 8 : - accdb_rw (extends accdb_ro) represents a read-write handle. 9 : 10 : - accdb_guardr is a read-only account lock guard 11 : - accdb_guardw is an exclusive account lock guard 12 : - accdb_spec is an account speculative read guard 13 : 14 : These APIs sit between the database layer (abstracts away backing 15 : stores and DB specifics) and the runtime layer (offer no runtime 16 : protections). */ 17 : 18 : #include "../fd_flamenco_base.h" 19 : #include "../../funk/fd_funk_rec.h" 20 : #include "../../funk/fd_funk_val.h" 21 : 22 : /* fd_accdb_ref_t is an opaque account database handle. */ 23 : 24 : struct fd_accdb_ref { 25 : ulong rec_laddr; 26 : ulong meta_laddr; 27 : uchar address[32]; /* only for vinyl requests */ 28 : }; 29 : typedef struct fd_accdb_ref fd_accdb_ref_t; 30 : 31 : /* fd_accdb_ro_t is a readonly account database handle. */ 32 : 33 : union fd_accdb_ro { 34 : fd_accdb_ref_t ref[1]; 35 : struct { 36 : fd_funk_rec_t const * rec; 37 : fd_account_meta_t const * meta; 38 : }; 39 : }; 40 : typedef union fd_accdb_ro fd_accdb_ro_t; 41 : 42 : FD_PROTOTYPES_BEGIN 43 : 44 : static inline void const * 45 3 : fd_accdb_ref_data_const( fd_accdb_ro_t const * ro ) { 46 3 : return (void *)( ro->meta+1 ); 47 3 : } 48 : 49 : static inline ulong 50 459 : fd_accdb_ref_data_sz( fd_accdb_ro_t const * ro ) { 51 459 : return ro->meta->dlen; 52 459 : } 53 : 54 : static inline ulong 55 3 : fd_accdb_ref_lamports( fd_accdb_ro_t const * ro ) { 56 3 : return ro->meta->lamports; 57 3 : } 58 : 59 : static inline void const * 60 3 : fd_accdb_ref_owner( fd_accdb_ro_t const * ro ) { 61 3 : return ro->meta->owner; 62 3 : } 63 : 64 : static inline uint 65 3 : fd_accdb_ref_exec_bit( fd_accdb_ro_t const * ro ) { 66 3 : return !!ro->meta->executable; 67 3 : } 68 : 69 : static inline ulong 70 0 : fd_accdb_ref_slot( fd_accdb_ro_t const * ro ) { 71 0 : return ro->meta->slot; 72 0 : } 73 : 74 : // void 75 : // fd_accdb_ref_lthash( fd_accdb_ro_t const * ro, 76 : // void * lthash ); 77 : 78 : FD_PROTOTYPES_END 79 : 80 : /* fd_accdb_rw_t is a writable database handle. Typically, writable 81 : handles are only available for invisible/in-prepartion records. 82 : In rare cases (e.g. when booting up), components may directly write 83 : to globally visible writable records. */ 84 : 85 : union fd_accdb_rw { 86 : fd_accdb_ref_t ref[1]; 87 : fd_accdb_ro_t ro [1]; 88 : struct { 89 : fd_funk_rec_t * rec; 90 : fd_account_meta_t * meta; 91 : uint published : 1; 92 : }; 93 : }; 94 : typedef union fd_accdb_rw fd_accdb_rw_t; 95 : 96 : FD_PROTOTYPES_BEGIN 97 : 98 : // void 99 : // fd_accdb_ref_clear( fd_accdb_rw_t * rw ); 100 : 101 : static inline ulong 102 0 : fd_accdb_ref_data_max( fd_accdb_rw_t * rw ) { 103 0 : ulong data_max; 104 0 : if( FD_UNLIKELY( __builtin_usubl_overflow( rw->rec->val_max, sizeof(fd_account_meta_t), &data_max ) ) ) { 105 0 : FD_LOG_CRIT(( "invalid rec->val_max %lu for account at rec %p", (ulong)rw->rec->val_max, (void *)rw->rec )); 106 0 : } 107 0 : return data_max; 108 0 : } 109 : 110 : static inline void * 111 0 : fd_accdb_ref_data( fd_accdb_rw_t * rw ) { 112 0 : return (void *)( rw->meta+1 ); 113 0 : } 114 : 115 : static inline void 116 : fd_accdb_ref_data_set( fd_accdb_rw_t * rw, 117 : void const * data, 118 0 : ulong data_sz ) { 119 0 : ulong data_max = fd_accdb_ref_data_max( rw ); 120 0 : if( FD_UNLIKELY( data_sz>data_max ) ) { 121 0 : FD_LOG_CRIT(( "attempted to write %lu bytes into a rec %p with only %lu bytes of data space", 122 0 : data_sz, (void *)rw->rec, data_max )); 123 0 : } 124 0 : fd_memcpy( fd_accdb_ref_data( rw ), data, data_sz ); 125 0 : rw->meta->dlen = (uint)data_sz; 126 0 : rw->rec->val_sz = (uint)( sizeof(fd_account_meta_t)+data_sz ) & (FD_FUNK_REC_VAL_MAX-1); 127 0 : } 128 : 129 : FD_FN_UNUSED static void 130 : fd_accdb_ref_data_sz_set( fd_accdb_rw_t * rw, 131 0 : ulong data_sz ) { 132 0 : ulong prev_sz = rw->meta->dlen; 133 0 : if( data_sz>prev_sz ) { 134 0 : /* Increasing size, zero out tail */ 135 0 : ulong data_max = fd_accdb_ref_data_max( rw ); 136 0 : if( FD_UNLIKELY( data_sz>data_max ) ) { 137 0 : FD_LOG_CRIT(( "attempted to write %lu bytes into a rec %p with only %lu bytes of data space", 138 0 : data_sz, (void *)rw->rec, data_max )); 139 0 : } 140 0 : void * tail = (uchar *)fd_accdb_ref_data( rw ) + prev_sz; 141 0 : fd_memset( tail, 0, data_sz-prev_sz ); 142 0 : } 143 0 : rw->meta->dlen = (uint)data_sz; 144 0 : rw->rec->val_sz = (uint)( sizeof(fd_account_meta_t)+data_sz ) & (FD_FUNK_REC_VAL_MAX-1); 145 0 : } 146 : 147 : static inline void 148 : fd_accdb_ref_lamports_set( fd_accdb_rw_t * rw, 149 0 : ulong lamports ) { 150 0 : rw->meta->lamports = lamports; 151 0 : } 152 : 153 : static inline void 154 : fd_accdb_ref_owner_set( fd_accdb_rw_t * rw, 155 0 : void const * owner ) { 156 0 : memcpy( rw->meta->owner, owner, 32UL ); 157 0 : } 158 : 159 : static inline void 160 : fd_accdb_ref_exec_bit_set( fd_accdb_rw_t * rw, 161 0 : uint exec_bit ) { 162 0 : rw->meta->executable = !!exec_bit; 163 0 : } 164 : 165 : static inline void 166 : fd_accdb_ref_slot_set( fd_accdb_rw_t * rw, 167 0 : ulong slot ) { 168 0 : rw->meta->slot = slot; 169 0 : } 170 : 171 : FD_PROTOTYPES_END 172 : 173 : /* fd_accdb_guardr_t tracks a rwlock being held as read-only. 174 : Destroying this guard object detaches the caller's thread from the 175 : rwlock. */ 176 : 177 : struct fd_accbd_guardr { 178 : fd_rwlock_t * rwlock; 179 : }; 180 : 181 : typedef struct fd_accdb_guardr fd_accdb_guardr_t; 182 : 183 : /* fd_accdb_guardw_t tracks an rwlock being held exclusively. 184 : Destroying this guard object detaches the caller's thread from the 185 : lock. */ 186 : 187 : struct fd_accdb_guardw { 188 : fd_rwlock_t * rwlock; 189 : }; 190 : 191 : typedef struct fd_accdb_guardw fd_accdb_guardw_t; 192 : 193 : /* fd_accdb_spec_t tracks a speculative access to a shared resource. 194 : Destroying this guard object marks the end of a speculative access. */ 195 : 196 : struct fd_accdb_spec { 197 : fd_funk_rec_key_t * keyp; /* shared key */ 198 : fd_funk_rec_key_t key; /* expected key */ 199 : }; 200 : 201 : typedef struct fd_accdb_spec fd_accdb_spec_t; 202 : 203 : /* fd_accdb_spec_test returns 1 if the shared resources has not been 204 : invalidated up until now. Returns 0 if the speculative access may 205 : have possibly seen a conflict (e.g. a torn read, a use-after-free, 206 : etc). */ 207 : 208 : static inline int 209 3 : fd_accdb_spec_test( fd_accdb_spec_t const * spec ) { 210 3 : fd_funk_rec_key_t key_found = FD_VOLATILE_CONST( *spec->keyp ); 211 3 : return !!fd_funk_rec_key_eq( &key_found, &spec->key ); 212 3 : } 213 : 214 : /* fd_accdb_spec_drop marks the end of a speculative access. */ 215 : 216 : static inline void 217 0 : fd_accdb_spec_drop( fd_accdb_spec_t * spec ) { 218 : /* Speculative accesses do not need central synchronization, so no 219 : need to inform the holder of the resource of this drop. */ 220 0 : (void)spec; 221 0 : } 222 : 223 : /* fd_accdb_peek_t is an ephemeral lock-free read-only pointer to an 224 : account in database cache. */ 225 : 226 : struct fd_accdb_peek { 227 : fd_accdb_ro_t acc[1]; 228 : fd_accdb_spec_t spec[1]; 229 : }; 230 : 231 : typedef struct fd_accdb_peek fd_accdb_peek_t; 232 : 233 : #endif /* HEADER_fd_src_flamenco_accdb_fd_accdb_ref_h */