Line data Source code
1 : #ifndef HEADER_fd_src_flamenco_accdb_fd_accdb_sync_h
2 : #define HEADER_fd_src_flamenco_accdb_fd_accdb_sync_h
3 :
4 : /* fd_accdb_sync.h provides synchronous blocking APIs for the account
5 : database. These are slow and should only be used for management ops. */
6 :
7 : #include "fd_accdb_user.h"
8 :
9 : /* Speculative zero-copy read API *************************************/
10 :
11 : FD_PROTOTYPES_BEGIN
12 :
13 : /* fd_accdb_peek_try starts a speculative read of an account. Queries
14 : the account database cache for the given address. On success,
15 : returns peek, which holds a speculative reference to an account. Use
16 : fd_accdb_peek_test to confirm whether peek is still valid.
17 :
18 : Typical usage like:
19 :
20 : fd_accdb_peek_t peek[1];
21 : if( !fd_accdb_peek( accdb, ... ) ) {
22 : ... account not found ...
23 : return;
24 : }
25 : ... speculatively process account ...
26 : if( fd_accdb_peek_test( peek )!=FD_ACCDB_SUCCESS ) {
27 : ... data race detected ...
28 : return;
29 : }
30 : ... happy path ... */
31 :
32 : static inline fd_accdb_peek_t *
33 : fd_accdb_peek( fd_accdb_user_t * accdb,
34 : fd_accdb_peek_t * peek,
35 : fd_funk_txn_xid_t const * xid,
36 0 : void const * address ) {
37 0 : return accdb->base.vt->peek( accdb, peek, xid, address );
38 0 : }
39 :
40 : /* fd_accdb_peek_test verifies whether a previously taken peek still
41 : refers to valid account data. Returns 1 if still valid, 0 if peek
42 : may have seen a conflict. */
43 :
44 : FD_FN_PURE static inline int
45 75 : fd_accdb_peek_test( fd_accdb_peek_t const * peek ) {
46 75 : return fd_accdb_spec_test( peek->spec );
47 75 : }
48 :
49 : /* fd_accdb_peek_drop releases the caller's interest in the account. */
50 :
51 : static inline void
52 0 : fd_accdb_peek_drop( fd_accdb_peek_t * peek ) {
53 0 : fd_accdb_spec_drop( peek->spec );
54 0 : }
55 :
56 : FD_PROTOTYPES_END
57 :
58 : /* In-place read APIs *************************************************/
59 :
60 : static inline fd_accdb_ro_t *
61 : fd_accdb_open_ro( fd_accdb_user_t * accdb,
62 : fd_accdb_ro_t * ro,
63 : fd_funk_txn_xid_t const * txn_id,
64 8856 : void const * address ) {
65 8856 : return accdb->base.vt->open_ro( accdb, ro, txn_id, address );
66 8856 : }
67 :
68 : static inline void
69 : fd_accdb_close_ro( fd_accdb_user_t * accdb,
70 27 : fd_accdb_ro_t * ro ) {
71 27 : accdb->base.vt->close_ro( accdb, ro );
72 27 : }
73 :
74 : /* FD_ACDB_RO_{BEGIN,END} provides RAII-style safe macros for
75 : fd_accdb_{open,close}_ro.
76 :
77 : Typical usage like:
78 :
79 : FD_ACCDB_RO_BEGIN( accdb, ro, xid, address ) {
80 : FD_LOG_NOTICE(( "Account has %lu lamports", fd_accdb_ref_lamports( ro ) ));
81 : }
82 : FD_ACCDB_RO_NOT_FOUND {
83 : FD_LOG_NOTICE(( "Account does not exist" ));
84 : }
85 : FD_ACCDB_RO_END; */
86 :
87 : struct fd_accdb_ro_scope_guard {
88 : fd_accdb_user_t * accdb;
89 : fd_accdb_ro_t * ro;
90 : };
91 : typedef struct fd_accdb_ro_scope_guard fd_accdb_ro_scope_guard_t;
92 :
93 : FD_FN_UNUSED static inline void
94 27 : fd_accdb_ro_scope_exit( fd_accdb_ro_scope_guard_t * guard ) {
95 27 : fd_accdb_close_ro( guard->accdb, guard->ro );
96 27 : }
97 :
98 : #define FD_ACCDB_RO_BEGIN( accdb__, handle, xid, address) \
99 27 : { \
100 27 : fd_accdb_ro_t handle[1]; \
101 27 : fd_accdb_user_t * accdb_ = (accdb__); \
102 27 : void const * addr_ = (address); \
103 27 : if( fd_accdb_open_ro( accdb, handle, (xid), addr_ ) ) { \
104 27 : fd_accdb_ro_scope_guard_t __attribute__((cleanup(fd_accdb_ro_scope_exit))) guard_ = \
105 27 : { .accdb=accdb_, .ro=handle }; \
106 27 : (void)guard_; \
107 27 : { \
108 : /* User-provided account found snippet */
109 : #define FD_ACCDB_RO_NOT_FOUND \
110 27 : } \
111 27 : } else { \
112 0 : { \
113 : /* User-provided account not found snippet */
114 : #define FD_ACCDB_RO_END \
115 0 : } \
116 0 : } \
117 27 : }
118 :
119 : /* In-place transactional write APIs **********************************/
120 :
121 : FD_PROTOTYPES_BEGIN
122 :
123 : /* fd_accdb_open_rw starts an account modification op. txn_xid names a
124 : non-rooted non-frozen fork graph node, and address identifies the
125 : account. If the account data buffer is smaller than data_max, it is
126 : resized (does not affect the data size, just the buffer capacity).
127 :
128 : If the CREATE flag is set and the account does not exist, returns a
129 : newly created account. If the CREATE flag is not set, returns NULL
130 : if the account does not exist.
131 :
132 : If the TRUNCATE flag is set, the account data size is set to zero.
133 : The account data buffer's capacity will still be data_max, but is
134 : left uninitialized. This is useful for callers that intend to
135 : replace the entire account.
136 :
137 : For the entire lifetime of an rw handle, the (txn_xid,address) pair
138 : MUST NOT be accessed by any other ro or rw operation. Violating this
139 : rule causes undefined behavior. The lifetime of an rw handle starts
140 : as soon as open_rw is called. It ends once all memory writes done
141 : after the close_rw call returns are visible to all other DB user
142 : threads.
143 :
144 : It is fine to do multiple open_rw/close_rw interactions with the same
145 : (txn_xid,address) pair assuming proper synchronization. Only the
146 : final state for a (txn_xid,address) pair is retained. */
147 :
148 : static inline fd_accdb_rw_t *
149 : fd_accdb_open_rw( fd_accdb_user_t * accdb,
150 : fd_accdb_rw_t * rw,
151 : fd_funk_txn_xid_t const * txn_id,
152 : void const * address,
153 : ulong data_max,
154 603 : int flags ) {
155 603 : return accdb->base.vt->open_rw( accdb, rw, txn_id, address, data_max, flags );
156 603 : }
157 :
158 : /* fd_accdb_close_rw publishes a previously prepared account write.
159 : Note that this function returns before memory writes have propagated
160 : to other threads, thus requires external synchronization. */
161 :
162 : static inline void
163 : fd_accdb_close_rw( fd_accdb_user_t * accdb,
164 15 : fd_accdb_rw_t * write ) { /* destroyed */
165 15 : accdb->base.vt->close_rw( accdb, write );
166 15 : }
167 :
168 : FD_PROTOTYPES_END
169 :
170 : #endif /* HEADER_fd_src_flamenco_accdb_fd_accdb_sync_h */
|