Line data Source code
1 : #include "fd_accdb_impl_v0.h"
2 :
3 : fd_account_meta_t const fd_accdb_meta_empty = {0};
4 :
5 : FD_FN_CONST ulong
6 0 : fd_accdb_v0_align( void ) {
7 0 : return alignof(fd_accdb_v0_t);
8 0 : }
9 :
10 : ulong
11 0 : fd_accdb_v0_footprint( ulong rec_cnt ) {
12 0 : ulong rec_sz;
13 0 : if( FD_UNLIKELY( __builtin_umull_overflow( rec_cnt, sizeof(fd_accdb_v0_rec_t), &rec_sz ) ) ) return 0UL;
14 0 : ulong sz;
15 0 : if( FD_UNLIKELY( __builtin_uaddl_overflow( sizeof(fd_accdb_v0_t), rec_sz, &sz ) ) ) return 0UL;
16 0 : return sz;
17 0 : }
18 :
19 : void *
20 : fd_accdb_v0_new( void * shmem,
21 0 : ulong rec_cnt ) {
22 :
23 0 : if( FD_UNLIKELY( !fd_accdb_v0_footprint( rec_cnt ) ) ) {
24 0 : FD_LOG_WARNING(( "invalid rec_cnt" ));
25 0 : return NULL;
26 0 : }
27 :
28 0 : fd_accdb_v0_t * v0 = (fd_accdb_v0_t *)shmem;
29 0 : memset( v0, 0, sizeof(fd_accdb_v0_t) );
30 0 : v0->rec_cnt = 0UL;
31 0 : v0->rec_max = rec_cnt;
32 0 : fd_rwlock_new( &v0->lock );
33 :
34 0 : FD_COMPILER_MFENCE();
35 0 : v0->magic = FD_ACCDB_V0_MAGIC;
36 0 : FD_COMPILER_MFENCE();
37 :
38 0 : return v0;
39 0 : }
40 :
41 : fd_accdb_v0_t *
42 0 : fd_accdb_v0_join( void * mem ) {
43 :
44 0 : if( FD_UNLIKELY( !mem ) ) {
45 0 : FD_LOG_WARNING(( "NULL accdb_v0" ));
46 0 : return NULL;
47 0 : }
48 0 : fd_accdb_v0_t * v0 = (fd_accdb_v0_t *)mem;
49 0 : if( FD_UNLIKELY( v0->magic!=FD_ACCDB_V0_MAGIC ) ) {
50 0 : FD_LOG_WARNING(( "bad magic" ));
51 0 : return NULL;
52 0 : }
53 :
54 0 : return v0;
55 0 : }
56 :
57 : void *
58 0 : fd_accdb_v0_leave( fd_accdb_v0_t * v0 ) {
59 0 : return v0;
60 0 : }
61 :
62 : void *
63 0 : fd_accdb_v0_delete( void * mem ) {
64 :
65 0 : if( FD_UNLIKELY( !mem ) ) {
66 0 : FD_LOG_WARNING(( "NULL accdb_v0" ));
67 0 : return NULL;
68 0 : }
69 0 : fd_accdb_v0_t * v0 = (fd_accdb_v0_t *)mem;
70 0 : if( FD_UNLIKELY( v0->magic!=FD_ACCDB_V0_MAGIC ) ) {
71 0 : FD_LOG_WARNING(( "bad magic" ));
72 0 : return NULL;
73 0 : }
74 0 : v0->magic = 0UL;
75 :
76 0 : fd_rwlock_write( &v0->lock );
77 0 : for( ulong i=0UL; i<v0->rec_cnt; i++ ) {
78 0 : if( FD_UNLIKELY( (!!v0->rec[ i ].writer_cnt) |
79 0 : (!!v0->rec[ i ].reader_cnt) ) ) {
80 0 : FD_LOG_CRIT(( "attempted to delete accdb_v0 with active users, aborting" ));
81 0 : }
82 0 : }
83 0 : fd_rwlock_unwrite( &v0->lock );
84 :
85 0 : memset( v0, 0, fd_accdb_v0_footprint( v0->rec_cnt ) );
86 0 : return v0;
87 0 : }
88 :
89 : fd_accdb_user_t *
90 : fd_accdb_user_v0_init( fd_accdb_user_t * accdb_,
91 0 : fd_accdb_v0_t * v0 ) {
92 :
93 0 : if( FD_UNLIKELY( !v0 || v0->magic!=FD_ACCDB_V0_MAGIC ) ) {
94 0 : FD_LOG_WARNING(( "invalid accdb_v0" ));
95 0 : return NULL;
96 0 : }
97 :
98 0 : fd_accdb_user_v0_t * accdb = fd_type_pun( accdb_ );
99 0 : memset( accdb, 0, sizeof(fd_accdb_user_v0_t) );
100 0 : accdb->base.accdb_type = FD_ACCDB_TYPE_V0;
101 0 : accdb->base.vt = &fd_accdb_user_v0_vt;
102 0 : accdb->v0 = v0;
103 0 : return accdb_;
104 0 : }
105 :
106 : void
107 0 : fd_accdb_user_v0_fini( fd_accdb_user_t * accdb ) {
108 0 : (void)accdb;
109 : /* FIXME consider asserting that the v0 reference count is zero */
110 0 : return;
111 0 : }
112 :
113 : static long
114 : find_key( fd_accdb_v0_t const * v0,
115 0 : void const * address ) {
116 0 : for( ulong i=0UL; i<v0->rec_cnt; i++ ) {
117 0 : if( 0==memcmp( &v0->rec[ i ].key, address, sizeof(fd_pubkey_t) ) ) {
118 0 : return (long)i;
119 0 : }
120 0 : }
121 0 : return -1L;
122 0 : }
123 :
124 : static void
125 : remove_rec( fd_accdb_v0_t * v0,
126 0 : long idx ) {
127 0 : if( v0->rec_cnt ) {
128 0 : ulong last_idx = v0->rec_cnt-1UL;
129 0 : v0->rec[ idx ] = v0->rec[ last_idx ];
130 0 : }
131 0 : v0->rec_cnt--;
132 0 : }
133 :
134 : static long
135 : push_rec( fd_accdb_v0_t * v0,
136 0 : void const * address ) {
137 0 : if( FD_UNLIKELY( v0->rec_cnt >= v0->rec_max ) ) return -1L;
138 0 : long idx = (long)v0->rec_cnt;
139 0 : fd_accdb_v0_rec_t * rec = &v0->rec[ idx ];
140 0 : memset( rec, 0, sizeof(fd_accdb_v0_rec_t) );
141 0 : memcpy( &rec->key, address, sizeof(fd_pubkey_t) );
142 0 : v0->rec_cnt++;
143 0 : return idx;
144 0 : }
145 :
146 : static ulong
147 0 : fd_accdb_user_v0_batch_max( fd_accdb_user_t * accdb ) {
148 0 : (void)accdb;
149 0 : return 1UL;
150 0 : }
151 :
152 : static fd_accdb_ro_t *
153 : fd_accdb_user_v0_open_ro( fd_accdb_user_t * accdb_,
154 : fd_accdb_ro_t * ro,
155 : fd_funk_txn_xid_t const * xid,
156 0 : void const * address ) {
157 0 : (void)xid;
158 0 : fd_accdb_user_v0_t * accdb = (fd_accdb_user_v0_t *)accdb_;
159 0 : fd_accdb_v0_t * v0 = accdb->v0;
160 :
161 0 : long idx = find_key( v0, address );
162 0 : fd_accdb_ro_t * found = NULL;
163 0 : if( idx>=0L ) {
164 0 : fd_accdb_v0_rec_t * rec = &v0->rec[ idx ];
165 0 : if( FD_UNLIKELY( rec->writer_cnt ) ) {
166 0 : FD_BASE58_ENCODE_32_BYTES( address, address_b58 );
167 0 : FD_LOG_CRIT(( "accdb_user_v0_open_ro failed: account %s is currently in use", address_b58 ));
168 0 : }
169 0 : rec->reader_cnt++;
170 :
171 0 : *ro = (fd_accdb_ro_t) {0};
172 0 : FD_STORE( fd_pubkey_t, ro->ref->address, rec->key );
173 0 : ro->ref->accdb_type = FD_ACCDB_TYPE_V0;
174 0 : ro->ref->ref_type = FD_ACCDB_REF_RO;
175 0 : ro->ref->user_data = 0UL;
176 0 : ro->meta = &rec->meta;
177 :
178 0 : accdb->base.ro_active++;
179 0 : found = ro;
180 0 : }
181 :
182 0 : return found;
183 0 : }
184 :
185 : void
186 : fd_accdb_user_v0_open_ro_multi( fd_accdb_user_t * accdb_,
187 : fd_accdb_ro_t * ro,
188 : fd_funk_txn_xid_t const * xid,
189 : void const * address,
190 0 : ulong cnt ) {
191 0 : fd_accdb_user_v0_t * accdb = (fd_accdb_user_v0_t *)accdb_;
192 0 : fd_accdb_v0_t * v0 = accdb->v0;
193 0 : fd_rwlock_write( &v0->lock );
194 0 : ulong addr_laddr = (ulong)address;
195 0 : for( ulong i=0UL; i<cnt; i++ ) {
196 0 : void const * addr_i = (void const *)( (ulong)addr_laddr + i*32UL );
197 0 : fd_accdb_ro_t * ro_i = fd_accdb_user_v0_open_ro( accdb_, &ro[i], xid, addr_i );
198 0 : if( !ro_i ) fd_accdb_ro_init_empty( &ro[i], addr_i );
199 0 : }
200 0 : fd_rwlock_unwrite( &v0->lock );
201 0 : }
202 :
203 : static void
204 : fd_accdb_user_v0_close_ro( fd_accdb_user_t * accdb,
205 0 : fd_accdb_ro_t * ro ) {
206 0 : fd_accdb_user_v0_t * user = (fd_accdb_user_v0_t *)accdb;
207 0 : fd_accdb_v0_t * v0 = user->v0;
208 :
209 0 : long idx = find_key( v0, ro->ref->address );
210 0 : if( FD_UNLIKELY( idx<0L ) ) {
211 0 : FD_BASE58_ENCODE_32_BYTES( ro->ref->address, address_b58 );
212 0 : FD_LOG_CRIT(( "accdb_user_v0_close_ro failed: account %s not found", address_b58 ));
213 0 : }
214 0 : fd_accdb_v0_rec_t * rec = &v0->rec[ idx ];
215 :
216 0 : if( FD_UNLIKELY( !rec->reader_cnt ||
217 0 : !user->base.ro_active ) ) {
218 0 : FD_LOG_CRIT(( "accdb_user_v0_close_ro failed: ref count underflow" ));
219 0 : }
220 0 : rec->reader_cnt--;
221 0 : user->base.ro_active--;
222 0 : }
223 :
224 : static fd_accdb_rw_t *
225 : fd_accdb_user_v0_open_rw( fd_accdb_user_t * accdb_,
226 : fd_accdb_rw_t * rw_,
227 : fd_funk_txn_xid_t const * xid,
228 : void const * address,
229 : ulong data_max,
230 0 : int flags ) {
231 0 : fd_accdb_user_v0_t * accdb = (fd_accdb_user_v0_t *)accdb_;
232 0 : fd_accdb_v0_t * v0 = accdb->v0;
233 0 : (void)xid;
234 :
235 0 : fd_accdb_rw_t * rw = NULL;
236 :
237 0 : int const flag_create = !!( flags & FD_ACCDB_FLAG_CREATE );
238 0 : int const flag_truncate = !!( flags & FD_ACCDB_FLAG_TRUNCATE );
239 0 : if( FD_UNLIKELY( flags & ~(FD_ACCDB_FLAG_CREATE|FD_ACCDB_FLAG_TRUNCATE) ) ) {
240 0 : FD_LOG_CRIT(( "invalid flags for open_rw: %#02x", (uint)flags ));
241 0 : }
242 :
243 0 : if( FD_UNLIKELY( data_max > FD_RUNTIME_ACC_SZ_MAX ) ) {
244 0 : FD_LOG_CRIT(( "invalid data_max %lu", data_max ));
245 0 : }
246 :
247 0 : long idx = find_key( v0, address );
248 0 : if( idx<0L ) {
249 0 : if( !flag_create ) return NULL;
250 0 : idx = push_rec( v0, address );
251 0 : if( FD_UNLIKELY( idx<0L ) ) FD_LOG_CRIT(( "accdb_user_v0_open_rw failed: cannot create account, out of memory" ));
252 0 : }
253 0 : rw = rw_;
254 :
255 0 : fd_accdb_v0_rec_t * rec = &v0->rec[ idx ];
256 0 : if( flag_truncate ) rec->meta.dlen = 0;
257 0 : accdb->base.rw_active++;
258 0 : rec->writer_cnt = 1;
259 0 : rec->reader_cnt = 0;
260 :
261 0 : *rw = (fd_accdb_rw_t) {0};
262 0 : memcpy( rw->ref->address, address, sizeof(fd_pubkey_t) );
263 0 : rw->ref->accdb_type = FD_ACCDB_TYPE_V0;
264 0 : rw->ref->ref_type = FD_ACCDB_REF_RW;
265 0 : rw->ref->user_data = 0UL;
266 0 : rw->meta = &rec->meta;
267 :
268 0 : return rw;
269 0 : }
270 :
271 : void
272 : fd_accdb_user_v0_open_rw_multi( fd_accdb_user_t * accdb_,
273 : fd_accdb_rw_t * rw,
274 : fd_funk_txn_xid_t const * xid,
275 : void const * address,
276 : ulong const * data_max,
277 : int flags,
278 0 : ulong cnt ) {
279 0 : fd_accdb_user_v0_t * accdb = (fd_accdb_user_v0_t *)accdb_;
280 0 : fd_accdb_v0_t * v0 = accdb->v0;
281 0 : fd_rwlock_write( &v0->lock );
282 0 : ulong addr_laddr = (ulong)address;
283 0 : for( ulong i=0UL; i<cnt; i++ ) {
284 0 : void const * addr_i = (void const *)( (ulong)addr_laddr + i*32UL );
285 0 : ulong dmax_i = data_max[i];
286 0 : fd_accdb_rw_t * rw_i = fd_accdb_user_v0_open_rw( accdb_, &rw[i], xid, addr_i, dmax_i, flags );
287 0 : if( !rw_i ) memset( &rw[i], 0, sizeof(fd_accdb_rw_t) );
288 0 : }
289 0 : fd_rwlock_unwrite( &v0->lock );
290 0 : }
291 :
292 : static void
293 : fd_accdb_user_v0_close_rw( fd_accdb_user_t * accdb,
294 0 : fd_accdb_rw_t * rw ) {
295 0 : fd_accdb_user_v0_t * user = (fd_accdb_user_v0_t *)accdb;
296 0 : fd_accdb_v0_t * v0 = user->v0;
297 :
298 0 : long idx = find_key( v0, rw->ref->address );
299 0 : if( FD_UNLIKELY( idx<0L ) ) {
300 0 : FD_BASE58_ENCODE_32_BYTES( rw->ref->address, address_b58 );
301 0 : FD_LOG_CRIT(( "accdb_user_v0_close_rw failed: account %s not found", address_b58 ));
302 0 : }
303 0 : fd_accdb_v0_rec_t * rec = &v0->rec[ idx ];
304 :
305 0 : if( FD_UNLIKELY( !rec->writer_cnt ||
306 0 : !user->base.rw_active ||
307 0 : user->base.ro_active ) ) {
308 0 : FD_LOG_CRIT(( "accdb_user_v0_close_rw failed: invalid ref count detected" ));
309 0 : }
310 0 : rec->writer_cnt--;
311 0 : user->base.rw_active--;
312 :
313 0 : if( rec->meta.lamports==0UL ) remove_rec( v0, idx );
314 0 : }
315 :
316 : static void
317 : fd_accdb_user_v0_close_ref( fd_accdb_user_t * accdb,
318 0 : fd_accdb_ref_t * ref ) {
319 0 : if( ref->accdb_type==FD_ACCDB_TYPE_NONE ) return;
320 0 : switch( ref->ref_type ) {
321 0 : case FD_ACCDB_REF_RO:
322 0 : fd_accdb_user_v0_close_ro( accdb, (fd_accdb_ro_t *)ref );
323 0 : break;
324 0 : case FD_ACCDB_REF_RW:
325 0 : fd_accdb_user_v0_close_rw( accdb, (fd_accdb_rw_t *)ref );
326 0 : break;
327 0 : default:
328 0 : FD_LOG_CRIT(( "invalid ref_type %u in fd_accdb_user_v0_close_ref", (uint)ref->ref_type ));
329 0 : }
330 0 : }
331 :
332 : void
333 : fd_accdb_user_v0_close_ref_multi( fd_accdb_user_t * accdb_,
334 : fd_accdb_ref_t * ref,
335 0 : ulong cnt ) {
336 0 : fd_accdb_user_v0_t * accdb = (fd_accdb_user_v0_t *)accdb_;
337 0 : fd_accdb_v0_t * v0 = accdb->v0;
338 0 : fd_rwlock_write( &v0->lock );
339 0 : for( ulong i=0UL; i<cnt; i++ ) {
340 0 : fd_accdb_ref_t * ref_i = &ref[i];
341 0 : fd_accdb_user_v0_close_ref( accdb_, ref_i );
342 0 : }
343 0 : fd_rwlock_unwrite( &v0->lock );
344 0 : }
345 :
346 : ulong
347 : fd_accdb_user_v0_rw_data_max( fd_accdb_user_t * accdb,
348 0 : fd_accdb_rw_t const * rw ) {
349 0 : (void)accdb;
350 0 : if( rw->ref->accdb_type==FD_ACCDB_TYPE_NONE ) {
351 0 : return rw->ref->user_data; /* data_max */
352 0 : }
353 0 : return FD_RUNTIME_ACC_SZ_MAX;
354 0 : }
355 :
356 : void
357 : fd_accdb_user_v0_rw_data_sz_set( fd_accdb_user_t * accdb,
358 : fd_accdb_rw_t * rw,
359 : ulong data_sz,
360 0 : int flags ) {
361 0 : (void)accdb;
362 0 : int flag_dontzero = !!( flags & FD_ACCDB_FLAG_DONTZERO );
363 0 : if( FD_UNLIKELY( flags & ~(FD_ACCDB_FLAG_DONTZERO) ) ) {
364 0 : FD_LOG_CRIT(( "invalid flags for rw_data_sz_set: %#02x", (uint)flags ));
365 0 : }
366 :
367 0 : ulong prev_sz = rw->meta->dlen;
368 0 : if( data_sz>prev_sz ) {
369 0 : if( FD_UNLIKELY( data_sz>FD_RUNTIME_ACC_SZ_MAX ) ) {
370 0 : FD_LOG_CRIT(( "attempted to write %lu bytes into a rec with only %lu bytes of data space",
371 0 : data_sz, FD_RUNTIME_ACC_SZ_MAX ));
372 0 : }
373 0 : if( !flag_dontzero ) {
374 0 : void * tail = (uchar *)fd_accdb_ref_data( rw ) + prev_sz;
375 0 : fd_memset( tail, 0, data_sz-prev_sz );
376 0 : }
377 0 : }
378 0 : rw->meta->dlen = (uint)data_sz;
379 0 : }
380 :
381 : fd_accdb_user_vt_t const fd_accdb_user_v0_vt = {
382 : .fini = fd_accdb_user_v0_fini,
383 : .batch_max = fd_accdb_user_v0_batch_max,
384 : .open_ro_multi = fd_accdb_user_v0_open_ro_multi,
385 : .open_rw_multi = fd_accdb_user_v0_open_rw_multi,
386 : .close_ref_multi = fd_accdb_user_v0_close_ref_multi,
387 : .rw_data_max = fd_accdb_user_v0_rw_data_max,
388 : .rw_data_sz_set = fd_accdb_user_v0_rw_data_sz_set
389 : };
|