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