Line data Source code
1 : #ifndef HEADER_fd_src_flamenco_accdb_fd_accdb_h
2 : #define HEADER_fd_src_flamenco_accdb_fd_accdb_h
3 :
4 : #include "fd_accdb_base.h"
5 : #include "fd_accdb_shmem.h"
6 :
7 : /* The accdb is a fork aware database that can be queried to get the
8 : current state of any accounts as-of a given fork, and update them. */
9 :
10 12600 : #define FD_ACCDB_ALIGN (128UL)
11 :
12 : /* Well-known file descriptor numbers for the accounts database backing
13 : file. Tiles inherit these from the parent process which dups the
14 : accounts file to these fds before fork+exec, so seccomp filters can
15 : pin syscalls to a fixed fd. fd 123462 is reserved by XDP. */
16 :
17 0 : #define FD_ACCDB_FD_RW (123461)
18 0 : #define FD_ACCDB_FD_RO (123460)
19 :
20 : struct fd_accdb_entry {
21 : uchar pubkey[ 32UL ];
22 : uchar owner[ 32UL ];
23 : ulong lamports;
24 : int executable;
25 :
26 : ulong data_len;
27 : uchar * data;
28 :
29 : uchar prior_owner[ 32UL ];
30 : ulong prior_lamports;
31 : int prior_executable;
32 : ulong prior_data_len;
33 : uchar * prior_data;
34 :
35 : int commit;
36 : int pd_write;
37 :
38 : int _writable;
39 : int _overwrite;
40 :
41 : ushort _fork_id;
42 : uint _generation;
43 : ulong _acc_map_idx;
44 :
45 : ulong _original_size_class;
46 : ulong _original_cache_idx;
47 :
48 : struct {
49 : ulong destination_cache_idx[ 8UL ];
50 : } _write;
51 : };
52 :
53 : typedef struct fd_accdb_entry fd_acc_t;
54 :
55 : FD_PROTOTYPES_BEGIN
56 :
57 : FD_FN_CONST ulong
58 : fd_accdb_align( void );
59 :
60 : FD_FN_CONST ulong
61 : fd_accdb_footprint( ulong max_live_slots );
62 :
63 : /* fd_accdb_new constructs the local joiner state for an accdb writer
64 : (or compaction tile). fd is an O_RDWR fd of the on-disk file.
65 :
66 : external_epoch_cnt and external_epoch_slots provide a list of
67 : additional epoch publish slots to scan during compaction's
68 : deferred-free reclamation. These point at memory owned by other
69 : processes (typically the per-tile fseq of read-only consumers like
70 : the rpc tile), mapped read-only into this joiner's address space.
71 : Each *external_epoch_slots[i] is updated by the owning RO joiner
72 : on each epoch-protected operation (and reset to ULONG_MAX when
73 : idle), and is used by this joiner's compaction scan to determine
74 : when on-disk partitions can be safely reclaimed.
75 :
76 : For joiners that do not need to track external RO consumers (i.e.
77 : any joiner that is not the compaction tile, or a writer-only
78 : topology), pass external_epoch_cnt=0 and external_epoch_slots=NULL.
79 : The pointer array is borrowed and must remain valid for the
80 : lifetime of the join. */
81 :
82 : void *
83 : fd_accdb_new( void * ljoin,
84 : fd_accdb_shmem_t * shmem,
85 : int fd,
86 : ulong external_epoch_cnt,
87 : ulong const ** external_epoch_slots );
88 :
89 : fd_accdb_t *
90 : fd_accdb_join( void * shaccdb );
91 :
92 : /* fd_accdb_join_readonly is the read-only counterpart of fd_accdb_new +
93 : fd_accdb_join. shmem_ro may point into a read-only mapping of the
94 : shmem region; the function will not write to it. my_epoch_slot_rw
95 : must point at a ulong owned by this joiner that it can write to
96 : (typically a private per-tile fseq that the accdb tile maps read-only
97 : and passes through external_epoch_slots[] in fd_accdb_new). fd_ro
98 : must be opened O_RDONLY on the same file the writer joiner opened RW.
99 :
100 : The joiner publishes its current epoch into *my_epoch_slot_rw on
101 : entry to each epoch-protected operation (and resets to ULONG_MAX on
102 : exit). The accdb tile's compaction scan observes this slot via its
103 : external_epoch_slots[] pointer and defers partition reclamation
104 : accordingly, the same way it does for in-shmem joiner_epochs[].
105 :
106 : Only fd_accdb_read_one_nocache, fd_accdb_exists, and
107 : fd_accdb_lamports are supported on a readonly join; any other API is
108 : undefined behavior. */
109 :
110 : fd_accdb_t *
111 : fd_accdb_join_readonly( void * ljoin,
112 : fd_accdb_shmem_t * shmem_ro,
113 : ulong * my_epoch_slot_rw,
114 : int fd_ro );
115 :
116 : /* fd_accdb_snapshot_load_{begin,end} toggle a mode on this writer
117 : joiner that causes layer-0 partition handoffs to backfill tiering
118 : for older snapshot-loaded partitions. Specifically, when a new
119 : partition P is opened at layer 0, the partition at P-2 is retiered
120 : to Warm (layer 1) and the partition at P-3 is retiered to Cold
121 : (layer 2). This compensates for the fact that snapshot-loaded
122 : accounts never get a second write and therefore never get promoted
123 : by normal compaction-driven tiering.
124 :
125 : The snapshot loader has exclusive write access to acc_pool. */
126 :
127 : void
128 : fd_accdb_snapshot_load_begin( fd_accdb_t * accdb );
129 :
130 : void
131 : fd_accdb_snapshot_load_end( fd_accdb_t * accdb );
132 :
133 : /* fd_accdb_snapshot_recover_delta appends into the accdb delta set the
134 : accounts modified at fork_id.
135 :
136 : This is intended to be used after booting off an incremental snapshot
137 : and allows the validator to create additional incremental snaps.
138 :
139 : Not thread safe: assumes no one but the calling thread is accessing
140 : accdb deltas. Returns 0 on success, -1 if the delta map is too small. */
141 :
142 : int
143 : fd_accdb_snapshot_recover_delta( fd_accdb_t * accdb,
144 : fd_accdb_fork_id_t fork_id );
145 :
146 : /* fd_accdb_snapshot_recovery_t captures layer-0 write head metadata.
147 : Used by fd_accdb_snapshot_{save,revert}_whead to save and restore
148 : accdb state across an incremental snapshot attempt. */
149 :
150 : struct fd_accdb_snapshot_recovery {
151 : ulong whead_val; /* whead[0].val */
152 : int has_partition; /* has_partition[0] */
153 : ulong partition_max; /* partition_max */
154 : ulong disk_current_bytes; /* disk_current_bytes metric */
155 : ulong savepoint_bytes_freed; /* bytes_freed of the save-point partition */
156 : };
157 :
158 : typedef struct fd_accdb_snapshot_recovery fd_accdb_snapshot_recovery_t;
159 :
160 : /* fd_accdb_snapshot_save_whead captures the current layer-0 write head,
161 : partition state, and disk_current_bytes metric into the provided
162 : recovery struct. Also captures the save-point partition's
163 : bytes_freed. */
164 :
165 : void
166 : fd_accdb_snapshot_save_whead( fd_accdb_t * accdb,
167 : fd_accdb_snapshot_recovery_t * out );
168 :
169 : /* fd_accdb_snapshot_revert_whead restores the layer-0 write head to a
170 : previously saved position.
171 :
172 : It internally waits for the pending background purge command to
173 : complete on T2 before releasing partitions, so the caller does not
174 : need to insert a separate wait_cmd barrier.
175 :
176 : Previously allocated partitions (with indices in the range
177 : [saved_partition_max, current partition_max)) are released back
178 : to the partition pool. disk_current_bytes is restored to the saved
179 : value rather than computed per-partition, and the save-point
180 : partition's bytes_freed and write_offset are reset. */
181 :
182 : void
183 : fd_accdb_snapshot_revert_whead( fd_accdb_t * accdb,
184 : fd_accdb_snapshot_recovery_t const * recover );
185 :
186 : /* fd_accdb_attach_child allocates a new fork as a child of
187 : parent_fork_id and returns the new fork's id. This must be done
188 : any time a new fork is being inserted into the accounts database,
189 : so that the accounts database can maintain ancestry information
190 : in order to support queries correctly.
191 :
192 : To create the initial root fork, pass a sentinel value with
193 : val==USHORT_MAX as parent_fork_id. This must be done exactly
194 : once, before any other fork operations.
195 :
196 : For non-root forks, parent_fork_id must refer to a fork that has
197 : already been attached. The ancestry must form a tree and it is
198 : undefined behavior to create cycles.
199 :
200 : If the fork pool is full but contains deferred forks, this call
201 : blocks until reader epochs drain and a deferred slot can be reused.
202 : The caller should never call this function unless there are either
203 : free fork ids or deferred ones. */
204 :
205 : fd_accdb_fork_id_t
206 : fd_accdb_attach_child( fd_accdb_t * accdb,
207 : fd_accdb_fork_id_t parent_fork_id );
208 :
209 : /* fd_accdb_advance_root advances the root of the accounts database to
210 : the given fork_id. fork_id must be a direct child of the current
211 : root (i.e. fork->parent_id equals the current root_fork_id).
212 :
213 : Any competing sibling forks (and their entire subtrees) are removed.
214 : For accounts updated on the newly rooted fork, any older versions on
215 : ancestor forks are tombstoned for later compaction. After this call
216 : the old root fork slot is freed and fork_id becomes the new root.
217 :
218 : IMPORTANT: The caller must guarantee that all outstanding
219 : acquire/release pairs on every sibling of fork_id (and their entire
220 : subtrees) have completed before calling advance_root. advance_root
221 : implicitly purges those sibling subtrees, which frees their fork pool
222 : slots for recycling.
223 :
224 : Once a fork is rooted, its generation becomes the new
225 : root_generation. Concurrent acquires that observe the new root will
226 : use the generation fast path (generation <= root_generation) for all
227 : accounts from that fork and its ancestors, bypassing descends_set
228 : entirely. This is what makes fork pool slot recycling safe: by the
229 : time a slot is freed and reusable, no reader will ever consult
230 : descends_set for the old fork_id. */
231 :
232 : void
233 : fd_accdb_advance_root( fd_accdb_t * accdb,
234 : fd_accdb_fork_id_t fork_id );
235 :
236 : /* fd_accdb_purge removes the provided fork and all of its descendants
237 : from the accounts database. This is an extremely rare operation,
238 : used to handle cases where a leader equivocated and produced two
239 : competing blocks for the same slot.
240 :
241 : All accounts written on the purged fork and any child or
242 : grandchild forks are removed from the index, and their disk
243 : space is freed for compaction. The ancestry information for all
244 : purged forks is also removed.
245 :
246 : IMPORTANT: The caller must guarantee that all outstanding
247 : acquire/release pairs on the purged fork and every descendant
248 : have completed before calling purge. The same fork pool slot
249 : recycling hazard described for advance_root applies here. */
250 :
251 : void
252 : fd_accdb_purge( fd_accdb_t * accdb,
253 : fd_accdb_fork_id_t fork_id );
254 :
255 : /* fd_accdb_acquire brings all of the requested accounts as-of the given
256 : fork_idx into the cache, and refcnts them in the cache so they cannot
257 : be evicted until later released.
258 :
259 : fork_idx is the fork index from replay to query as-of, and must exist
260 : for the entire duration of the acquire call, meaning, whoever is
261 : acquiring must have a refcnt on the bank corresponding to fork_idx,
262 : and not release it until after the accounts are acquired. It is safe
263 : to release the bank after the acquire call returns, and this will not
264 : cause the acquired accounts to be evicted from the cache.
265 :
266 : The refcnt does not have to be on the bank of fork_idx itself: a
267 : refcnt on a live child bank of fork_idx also suffices. This is the
268 : executor's pattern, it holds a refcnt on the executing child bank
269 : and read-only acquires implicit programdata on that bank's (frozen)
270 : parent fork. It works because a fork with a live (refcnt>0) child
271 : bank can be neither advanced-past nor purged, so fork_idx cannot be
272 : recycled out from under the acquire. advance_root(fork_idx) itself
273 : (rooting the queried fork) IS permitted concurrently with a read-only
274 : acquire on fork_idx (see the THREADING MODEL section); what remains
275 : forbidden is advancing PAST fork_idx or purging it while any acquire
276 : on it is outstanding.
277 :
278 : pubkeys_cnt is the number of accounts to acquire, and pubkeys is an
279 : array of pointers to the 32-byte pubkeys of the accounts to acquire.
280 : writable is an array of flags indicating whether each corresponding
281 : account in pubkeys is being acquired for read (0) or write (1).
282 : Writes provide a temporary buffer of 10MiB in all cases, which the
283 : caller can use for staging changes to the data, and this allows
284 : account resizing, or cancelling of any data written (for example if a
285 : transaction fails) without needing to restore it. If an account is
286 : acquired for write, the caller must set the commit bit on the acc
287 : to non-zero to have the changes written back to the database on
288 : release, or leave it at zero to discard the changes. The commit bit
289 : must be set even if only the metadata has changed.
290 :
291 : IMPORTANT: The caller must guarantee that for any given (pubkey,
292 : fork) pair, there is no concurrent acquire that holds a writable
293 : acc while another acquire for the same account on the same fork is
294 : outstanding (whether readable or writable). Specifically:
295 :
296 : - Multiple concurrent read-only acquires of the same account on the
297 : same fork are permitted.
298 : - A writable acquire of an account on a given fork must not overlap
299 : with any other acquire (read or write) of that same account on
300 : that same fork.
301 : - Acquires of the same account on _different_ forks are always safe
302 : and may overlap freely, provided that all releases on an ancestor
303 : fork have completed before any acquire on a descendant fork
304 : begins. In particular, a fork must finish all of its transaction
305 : execution (including committing or cancelling every writable
306 : account) before a child fork is attached and begins acquiring.
307 : This is naturally guaranteed by the replay scheduler, which does
308 : not activate a child block until the parent block is fully done.
309 : Concurrent acquires across unrelated sibling forks have no
310 : ordering requirement.
311 : - A read-only acquire on a frozen ancestor fork may begin after
312 : descendant-fork acquires (read or write) have already begun. The
313 : executor relies on this: while a child bank executes (writably
314 : acquiring its own-fork accounts), it also read-only acquires the
315 : program's implicit programdata on the frozen parent fork. This
316 : is safe because the parent is frozen, no writer ever commits to
317 : it so the read-only acquire cannot overlap any same-fork write,
318 : and read-only acquires never mutate acc pool or fork state.
319 :
320 : Violating this contract is undefined behavior and will likely crash
321 : with an assertion failure inside the cache refcount logic. In
322 : practice, these constraints are naturally satisfied by the Solana
323 : execution model: each transaction has exclusive write locks on its
324 : writable accounts within a slot, the scheduler ensures no two
325 : concurrent transactions write to the same account on the same fork,
326 : and the replay scheduler serializes parent block completion before
327 : child block activation on the same fork chain.
328 :
329 : When a writable account is committed as an "overwrite" (same
330 : fork), the acc pool element's metadata fields (size, lamports,
331 : offset) are mutated in place, and the cache line's owner field is
332 : updated. This is safe because these mutations
333 : only happen on the acc element whose generation matches the
334 : committing fork. A concurrent acquire on a different fork cannot
335 : observe an in-place mutation of the same acc element for a child fork
336 : to even exist, the parent must be frozen and no longer undergoing
337 : modifications. All acc pool fields are effectively immutable from
338 : the perspective of any concurrent cross-fork reader.
339 :
340 : out_accs is an array of pubkeys_cnt cache accs to be filled in
341 : with the acquired accounts. The cache will fill the owner, lamports,
342 : data_len, and data fields of each acc if the acquire is successful,
343 : and the account exists. If the account does not exist, the lamports
344 : field will be set to zero and other fields are undefined. */
345 :
346 : void
347 : fd_accdb_acquire( fd_accdb_t * accdb,
348 : fd_accdb_fork_id_t fork_id,
349 : ulong pubkeys_cnt,
350 : uchar const * const * pubkeys,
351 : int * writable,
352 : fd_acc_t * out_accs );
353 :
354 : void
355 : fd_accdb_acquire_a( fd_accdb_t * accdb,
356 : fd_accdb_fork_id_t fork_id,
357 : ulong pubkeys_cnt,
358 : uchar const * const * pubkeys,
359 : int * writable,
360 : fd_acc_t * out_accs );
361 :
362 : void
363 : fd_accdb_acquire_b( fd_accdb_t * accdb,
364 : fd_accdb_fork_id_t fork_id,
365 : ulong reserved_cnt,
366 : ulong pubkeys_cnt,
367 : uchar const * const * pubkeys,
368 : int * writable,
369 : fd_acc_t * out_accs );
370 :
371 : /* fd_accdb_release releases previously acquired accounts back to the
372 : cache, and if any of the released writable accounts have their commit
373 : bit set, the cache will write the changes back to the database. The
374 : caller must guarantee that the accs being released were previously
375 : acquired and not yet released, and that the pubkeys in the accs
376 : match the pubkeys of the acquired accounts. The accs need not be
377 : a specific set that was acquired together, although this is
378 : recommended. The fork that each acc refers to must still exist
379 : (not yet purged or advanced past) at the time of release. This
380 : includes forks that would be implicitly purged by a concurrent
381 : advance_root on a sibling — the caller must ensure advance_root
382 : is not called until all releases on affected forks have completed.
383 : Releasing accounts for a fork that has been purged or recycled is
384 : undefined behavior. */
385 :
386 : void
387 : fd_accdb_release( fd_accdb_t * accdb,
388 : ulong accs_cnt,
389 : fd_acc_t * accs );
390 :
391 : void
392 : fd_accdb_release_ab( fd_accdb_t * accdb,
393 : ulong accs_cnt,
394 : fd_acc_t * accs,
395 : ulong execs_cnt,
396 : fd_acc_t * execs );
397 :
398 : fd_acc_t
399 : fd_accdb_read_one( fd_accdb_t * accdb,
400 : fd_accdb_fork_id_t fork_id,
401 : uchar const * pubkey );
402 :
403 : fd_acc_t
404 : fd_accdb_write_one( fd_accdb_t * accdb,
405 : fd_accdb_fork_id_t fork_id,
406 : uchar const * pubkey );
407 :
408 : void
409 : fd_accdb_unwrite_one( fd_accdb_t * accdb,
410 : fd_acc_t * acc );
411 :
412 : void
413 : fd_accdb_unread_one( fd_accdb_t * accdb,
414 : fd_acc_t * acc );
415 :
416 : int
417 : fd_accdb_exists( fd_accdb_t * accdb,
418 : fd_accdb_fork_id_t fork_id,
419 : uchar const * pubkey );
420 :
421 : /* fd_accdb_probe_pd_this_fork checks whether the newest version of
422 : pubkey visible on fork_id was committed on fork_id itself. If so,
423 : returns 1 and sets *out_pd_write to that version's pd_write flag,
424 : *out_data_len to its data length, and *out_lamports to its lamport
425 : balance. Otherwise returns 0, sets *out_pd_write to 0, and leaves
426 : *out_data_len and *out_lamports untouched.
427 :
428 : Reads only metadata, not account data. out_pd_write deliberately
429 : ignores lamports: a programdata closed this slot is a lamports==0
430 : tombstone that must still report pd_write=1 so the loader's
431 : DelayVisibility gate fires. out_lamports is reported separately so
432 : that callers doing account deadness checks have the current fork's
433 : deadness.
434 :
435 : Note that out_lamports and out_data_len are not read atomically.
436 : Caller is responsible for ensuring ordering if racing is not
437 : acceptable.
438 :
439 : Full join only. */
440 :
441 : int
442 : fd_accdb_probe_pd_this_fork( fd_accdb_t * accdb,
443 : fd_accdb_fork_id_t fork_id,
444 : uchar const * pubkey,
445 : int * out_pd_write,
446 : ulong * out_data_len,
447 : ulong * out_lamports );
448 :
449 : /* fd_accdb_read_one_nocache reads one account at fork_id into
450 : caller-provided output buffers. Suitable for processes that mmap the
451 : accdb data region read-only: it never mutates any cache line, index
452 : entry, or record. The only write it makes into accdb shmem is
453 : publishing this joiner's epoch (to hold off compaction for the
454 : duration of the read), and that is done through a separately-mmap'd
455 : writable page aliasing the joiner's own epoch slot, not the read-only
456 : region.
457 :
458 : out_owner must point at a 32-byte buffer. out_data must point at a
459 : buffer of at least FD_RUNTIME_ACC_SZ_MAX (10 MiB) bytes, the maximum
460 : account data size; the function does not bound-check against the
461 : account's actual length. On a cache hit the bytes are memcpy'd from
462 : the cache slot using a try-read-test (ABA) loop; on a miss the owner
463 : and data are preadv2'd from the disk fd passed at join time, scattered
464 : into out_owner and out_data via iovec (looping on short reads).
465 :
466 : If the account does not exist, *out_lamports is set to zero and the
467 : other outputs are undefined; otherwise *out_lamports is non-zero and
468 : out_executable, out_owner, out_data, and out_data_len are all filled
469 : in.
470 :
471 : The function takes no reference; nothing needs to be released. */
472 :
473 : void
474 : fd_accdb_read_one_nocache( fd_accdb_t * accdb,
475 : fd_accdb_fork_id_t fork_id,
476 : uchar const * pubkey,
477 : ulong * out_lamports,
478 : int * out_executable,
479 : uchar * out_owner,
480 : uchar * out_data,
481 : ulong * out_data_len );
482 :
483 : /* fd_accdb_lamports returns the lamports of the account at fork_id, or
484 : zero if the account does not exist. */
485 :
486 : ulong
487 : fd_accdb_lamports( fd_accdb_t * accdb,
488 : fd_accdb_fork_id_t fork_id,
489 : uchar const * pubkey );
490 :
491 : /* fd_accdb_reset reinitializes the accdb to the state immediately after
492 : fd_accdb_new. All in-memory index state is cleared and all pool
493 : joins are re-established. The caller is responsible for truncating
494 : the on-disk file separately (e.g. via the snapwr tile).
495 :
496 : The caller must guarantee that no other thread is concurrently
497 : accessing the accdb (no outstanding acquires, no background work). */
498 :
499 : void
500 : fd_accdb_reset( fd_accdb_t * accdb );
501 :
502 : /* fd_accdb_snapshot_write_one inserts or replaces an account during
503 : snapshot loading. Returns -1 if the write was ignored (an existing
504 : acc has a higher slot), 1 if a new acc was inserted, 2 if an
505 : existing acc was replaced. When 2 is returned, *out_replaced_lamports
506 : is set to the lamports of the replaced acc. Otherwise it is set to
507 : 0. out_replaced_lamports must be non-NULL.
508 :
509 : slot must be <= UINT_MAX. The slot is held in a 32-bit scratch field
510 : during snapshot loading; the accdb format must be widened before
511 : Solana reaches slot 2^32. Passing a larger slot crashes the
512 : process.
513 :
514 : fork_id controls recovery behavior:
515 :
516 : USHORT_MAX, full-snapshot mode. Existing entries with the same
517 : pubkey are replaced in-place. No txn entries are
518 : created.
519 :
520 : other, incremental-snapshot mode. Cross-snapshot overrides
521 : (existing entry from a different fork) insert a NEW
522 : acc_pool entry alongside the old one and create a txn
523 : record on fork_id, so fd_accdb_purge can revert the
524 : incremental writes on failure. Intra-fork duplicates
525 : (same pubkey from the same fork) are still replaced
526 : in-place. */
527 :
528 : int
529 : fd_accdb_snapshot_write_one( fd_accdb_t * accdb,
530 : fd_accdb_fork_id_t fork_id,
531 : uchar const * pubkey,
532 : ulong slot,
533 : ulong lamports,
534 : ulong data_len,
535 : int executable,
536 : ulong * out_replaced_lamports );
537 :
538 : /* fd_accdb_snapshot_write_batch processes up to 8 accounts at once,
539 : using software prefetching to overlap hash chain memory latency with
540 : useful work. This function is not thread safe and must not be called
541 : concurrently. Each pubkey[i] points to a 32-byte public key.
542 : *out_replaced_lamports is set to the sum of the lamports of all
543 : accounts replaced by this batch (i.e. the previous lamports value of
544 : each account whose acc was overwritten). *out_ignored_lamports is
545 : set to the sum of the lamports of all accounts ignored by this batch
546 : (i.e. the lamports of each input account whose write was dropped
547 : because an acc with a higher slot already exists). Returns 0 on
548 : success, -1 if the batch contained two entries with the same pubkey
549 : (a corrupt-snapshot signal — the caller should flag the snapshot
550 : malformed). Output counters are not meaningful when -1 is returned.
551 :
552 : Each slots[i] must be <= UINT_MAX (see fd_accdb_snapshot_write_one
553 : for the rationale). Passing a larger slot crashes the process.
554 :
555 : fork_id has the same semantics as in fd_accdb_snapshot_write_one:
556 : USHORT_MAX for full-snapshot mode, otherwise incremental mode with
557 : txn tracking on the specified fork. */
558 :
559 : int
560 : fd_accdb_snapshot_write_batch( fd_accdb_t * accdb,
561 : fd_accdb_fork_id_t fork_id,
562 : ulong cnt,
563 : uchar const * const pubkeys[],
564 : ulong const slots[],
565 : ulong const lamports[],
566 : ulong const data_lens[],
567 : int const executables[],
568 : ulong * accounts_ignored,
569 : ulong * accounts_replaced,
570 : ulong * accounts_loaded,
571 : ulong * out_replaced_lamports,
572 : ulong * out_ignored_lamports );
573 :
574 : /* fd_accdb_background performs one unit of background work.
575 :
576 : THREADING MODEL
577 :
578 : The accdb API is split across three thread roles:
579 :
580 : T1 (replay): calls attach_child, advance_root, purge, acquire, and
581 : release. attach_child runs inline on T1. advance_root and
582 : purge submit a command into a shared- memory slot and return
583 : immediately; the heavy work is deferred to T2.
584 :
585 : T2 (accdb tile / background): calls fd_accdb_background repeatedly.
586 : This is the only function T2 should call.
587 :
588 : T3 (executor tiles, 1..N): call acquire and release.
589 :
590 : acquire and release may be called concurrently from T1 and any number
591 : of T3 threads.
592 :
593 : Read-only acquire/release on a fork F may run concurrently with
594 : advance_root(F) (rooting F itself).
595 :
596 : fd_accdb_background must be called from exactly one thread (T2). It
597 : must not be called concurrently with itself.
598 :
599 : BEHAVIOR
600 :
601 : First checks for a pending advance_root or purge command from T1; if
602 : one is present it executes the command, sets *charge_busy to 1, and
603 : returns immediately without doing compaction. Otherwise, attempts one
604 : step of compaction at each layer, setting *charge_busy if work was
605 : done. */
606 :
607 : void
608 : fd_accdb_background( fd_accdb_t * accdb,
609 : int * charge_busy );
610 :
611 : /* fd_accdb_shmetrics returns a pointer to the shared metrics counters
612 : for the given accdb instance. The returned pointer remains valid
613 : for the lifetime of the underlying shmem. */
614 :
615 : fd_accdb_shmem_metrics_t const *
616 : fd_accdb_shmetrics( fd_accdb_t * accdb );
617 :
618 : /* fd_accdb_metrics returns a pointer to the per-thread metrics counters
619 : for the given accdb instance. The returned pointer remains valid
620 : for the lifetime of the underlying shmem. */
621 :
622 : fd_accdb_metrics_t const *
623 : fd_accdb_metrics( fd_accdb_t * accdb );
624 :
625 : /* fd_accdb_flush_metrics publishes this joiner's pending layer-0 write
626 : metrics. Normal layer-0 writes defer these metrics by default.
627 :
628 : NOTE: A flush delayed past partition reuse can credit old counters
629 : to the new partition. The impact on metrics accuracy is expected
630 : to be rare and small because partitions are rarely reused and
631 : metrics flush often. */
632 :
633 : void
634 : fd_accdb_flush_metrics( fd_accdb_t * accdb );
635 :
636 : /* fd_accdb_cache_class_occupancy snapshots the current per-size-class
637 : cache occupancy and capacity into the caller-provided arrays, each
638 : of which must have FD_ACCDB_CACHE_CLASS_CNT entries. used[c] is the
639 : number of slots in class c that currently hold a cache acc (i.e.
640 : slots that have been allocated lazily and are not sitting in the
641 : free list). max[c] is the total slot capacity of class c. Reads
642 : are done with relaxed (volatile) loads and may be momentarily
643 : inconsistent with each other under contention. */
644 :
645 : void
646 : fd_accdb_cache_class_occupancy( fd_accdb_t * accdb,
647 : ulong * used,
648 : ulong * max,
649 : ulong * reserved );
650 :
651 : /* fd_accdb_cache_class_thresholds returns the per-size-class preeviction
652 : thresholds, expressed as used-slot counts (so they're directly
653 : comparable to occupancy.used and occupancy.max). Each output array
654 : must have FD_ACCDB_CACHE_CLASS_CNT entries. target_used[c] is the
655 : used count the background preevict pass tries to drive towards (max -
656 : cache_free_target). low_water_used[c] is the used count at which the
657 : preevict pass starts firing (max - cache_free_low_water). Both are
658 : set once at init and are stable for the lifetime of the cache. */
659 :
660 : void
661 : fd_accdb_cache_class_thresholds( fd_accdb_t * accdb,
662 : ulong * target_used,
663 : ulong * low_water_used );
664 :
665 : /* FD_ACCDB_METRICS_WRITE publishes the per-joiner accdb runtime metrics
666 : for tile prefix TILE. TILE must be a tile that declares the
667 : AccdbAccountAcquired/... counters in metrics.xml (e.g. EXECLE,
668 : EXECRP, REPLAY, TOWER, ACCDB). m must be a fd_accdb_metrics_t const *
669 : for the joiner whose counters should be published. */
670 :
671 0 : #define FD_ACCDB_METRICS_WRITE( TILE, m ) do { \
672 0 : fd_accdb_metrics_t const * _m = (m); \
673 0 : FD_MCNT_ENUM_COPY( TILE, ACCDB_ACCOUNT_ACQUIRED, _m->accounts_acquired_per_class ); \
674 0 : FD_MCNT_ENUM_COPY( TILE, ACCDB_ACCOUNT_WRITABLE_ACQUIRED, _m->writable_accounts_acquired_per_class ); \
675 0 : FD_MCNT_ENUM_COPY( TILE, ACCDB_ACCOUNT_EVICTED, _m->accounts_evicted_per_class ); \
676 0 : FD_MCNT_ENUM_COPY( TILE, ACCDB_ACCOUNT_COMMITTED_NEW, _m->accounts_committed_new_per_class ); \
677 0 : FD_MCNT_ENUM_COPY( TILE, ACCDB_ACCOUNT_COMMITTED_OVERWRITE, _m->accounts_committed_overwrite_per_class ); \
678 0 : FD_MCNT_ENUM_COPY( TILE, ACCDB_ACCOUNT_NOT_FOUND, _m->accounts_not_found_per_class ); \
679 0 : FD_MCNT_SET( TILE, ACCDB_ACCOUNT_WAITED, _m->accounts_waited ); \
680 0 : FD_MCNT_SET( TILE, ACCDB_BATCH_ACQUIRED, _m->acquire_calls ); \
681 0 : FD_MCNT_SET( TILE, ACCDB_ACQUIRE_FAILED, _m->acquire_failed ); \
682 0 : FD_MCNT_SET( TILE, ACCDB_BYTES_READ, _m->bytes_read ); \
683 0 : FD_MCNT_SET( TILE, ACCDB_READ_OPERATION, _m->read_ops ); \
684 0 : FD_MCNT_SET( TILE, ACCDB_BYTES_WRITTEN, _m->bytes_written ); \
685 0 : FD_MCNT_SET( TILE, ACCDB_WRITE_OPERATION, _m->write_ops ); \
686 0 : FD_MCNT_SET( TILE, ACCDB_BYTES_COPIED, _m->bytes_copied ); \
687 0 : } while(0)
688 :
689 : /* FD_ACCDB_METRICS_WRITE_RO is the read-only joiner subset of
690 : FD_ACCDB_METRICS_WRITE. It only emits the counters that
691 : fd_accdb_read_one_nocache touches; tiles that join readonly
692 : (e.g. RPC) declare only this subset of counters in metrics.xml. */
693 :
694 0 : #define FD_ACCDB_METRICS_WRITE_RO( TILE, m ) do { \
695 0 : fd_accdb_metrics_t const * _m = (m); \
696 0 : FD_MCNT_ENUM_COPY( TILE, ACCDB_ACCOUNT_ACQUIRED, _m->accounts_acquired_per_class ); \
697 0 : FD_MCNT_ENUM_COPY( TILE, ACCDB_ACCOUNT_NOT_FOUND, _m->accounts_not_found_per_class ); \
698 0 : FD_MCNT_SET( TILE, ACCDB_ACCOUNT_WAITED, _m->accounts_waited ); \
699 0 : FD_MCNT_SET( TILE, ACCDB_BATCH_ACQUIRED, _m->acquire_calls ); \
700 0 : FD_MCNT_SET( TILE, ACCDB_BYTES_READ, _m->bytes_read ); \
701 0 : FD_MCNT_SET( TILE, ACCDB_READ_OPERATION, _m->read_ops ); \
702 0 : FD_MCNT_SET( TILE, ACCDB_BYTES_COPIED, _m->bytes_copied ); \
703 0 : } while(0)
704 :
705 : FD_PROTOTYPES_END
706 :
707 : #endif /* HEADER_fd_src_flamenco_accdb_fd_accdb_h */
|