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 : /* In-place read APIs *************************************************/
10 :
11 : static inline void
12 : fd_accdb_close_ref( fd_accdb_user_t * accdb,
13 23745 : fd_accdb_ref_t * ref ) {
14 23745 : if( FD_UNLIKELY( ref->accdb_type==FD_ACCDB_TYPE_NONE ) ) return;
15 13950 : accdb->base.vt->close_ref_multi( accdb, ref, 1UL );
16 13950 : }
17 :
18 : static inline fd_accdb_ro_t *
19 : fd_accdb_open_ro( fd_accdb_user_t * accdb,
20 : fd_accdb_ro_t * ro,
21 : fd_funk_txn_xid_t const * txn_id,
22 16770 : void const * address ) {
23 16770 : accdb->base.vt->open_ro_multi( accdb, ro, txn_id, address, 1UL );
24 16770 : if( fd_accdb_ref_lamports( ro )==0UL ) {
25 12810 : fd_accdb_close_ref( accdb, ro->ref );
26 12810 : return NULL;
27 12810 : }
28 3960 : return ro;
29 16770 : }
30 :
31 : static inline void
32 : fd_accdb_close_ro( fd_accdb_user_t * accdb,
33 4017 : fd_accdb_ro_t * ro ) {
34 4017 : fd_accdb_close_ref( accdb, ro->ref );
35 4017 : }
36 :
37 : /* In-place transactional write APIs **********************************/
38 :
39 : FD_PROTOTYPES_BEGIN
40 :
41 : /* fd_accdb_open_rw starts an account modification op. txn_xid names a
42 : non-rooted non-frozen fork graph node, and address identifies the
43 : account. If the account data buffer is smaller than data_max, it is
44 : resized (does not affect the data size, just the buffer capacity).
45 :
46 : If the CREATE flag is set and the account does not exist, returns a
47 : newly created account. If the CREATE flag is not set, returns NULL
48 : if the account does not exist.
49 :
50 : If the TRUNCATE flag is set, the account data size is set to zero.
51 : The account data buffer's capacity will still be data_max, but is
52 : left uninitialized. This is useful for callers that intend to
53 : replace the entire account.
54 :
55 : For the entire lifetime of an rw handle, the (txn_xid,address) pair
56 : MUST NOT be accessed by any other ro or rw operation. Violating this
57 : rule causes undefined behavior. The lifetime of an rw handle starts
58 : as soon as open_rw is called. It ends once all memory writes done
59 : after the close_rw call returns are visible to all other DB user
60 : threads.
61 :
62 : It is fine to do multiple open_rw/close_rw interactions with the same
63 : (txn_xid,address) pair assuming proper synchronization. Only the
64 : final state for a (txn_xid,address) pair is retained. */
65 :
66 : static inline fd_accdb_rw_t *
67 : fd_accdb_open_rw( fd_accdb_user_t * accdb,
68 : fd_accdb_rw_t * rw,
69 : fd_funk_txn_xid_t const * txn_id,
70 : void const * address,
71 : ulong data_max,
72 6933 : int flags ) {
73 6933 : accdb->base.vt->open_rw_multi( accdb, rw, txn_id, address, &data_max, flags, 1UL );
74 6933 : if( rw->ref->accdb_type==FD_ACCDB_TYPE_NONE ) return NULL;
75 6918 : return rw;
76 6933 : }
77 :
78 : /* fd_accdb_close_rw publishes a previously prepared account write.
79 : Note that this function returns before memory writes have propagated
80 : to other threads, thus requires external synchronization. */
81 :
82 : static inline void
83 : fd_accdb_close_rw( fd_accdb_user_t * accdb,
84 6918 : fd_accdb_rw_t * rw ) { /* destroyed */
85 6918 : fd_accdb_close_ref( accdb, rw->ref );
86 6918 : }
87 :
88 : /* fd_accdb_ref_data_max returns the data capacity of an account. */
89 :
90 : static inline ulong
91 : fd_accdb_ref_data_max( fd_accdb_user_t * accdb,
92 0 : fd_accdb_rw_t * rw ) {
93 0 : return accdb->base.vt->rw_data_max( accdb, rw );
94 0 : }
95 :
96 : /* fd_accdb_ref_data_sz_set expands/truncates the data size of an
97 : account. Assumes that the account has sufficient capacity
98 : (fd_accdb_ref_data_max). If an increase of the account size was
99 : requested, zero-initializes the tail region, unless FLAG_DONTZERO is
100 : set. */
101 :
102 : static inline void
103 : fd_accdb_ref_data_sz_set( fd_accdb_user_t * accdb,
104 : fd_accdb_rw_t * rw,
105 : ulong data_sz,
106 744 : int flags ) {
107 744 : accdb->base.vt->rw_data_sz_set( accdb, rw, data_sz, flags );
108 744 : }
109 :
110 : /* fd_accdb_ref_data_set replaces the data content of an account.
111 : Assumes that the account has sufficient capacity
112 : (fd_accdb_ref_data_max). */
113 :
114 : FD_FN_UNUSED static void
115 : fd_accdb_ref_data_set( fd_accdb_user_t * accdb,
116 : fd_accdb_rw_t * rw,
117 : void const * data,
118 744 : ulong data_sz ) {
119 744 : fd_accdb_ref_data_sz_set( accdb, rw, data_sz, FD_ACCDB_FLAG_DONTZERO );
120 744 : fd_memcpy( fd_accdb_ref_data( rw ), data, data_sz );
121 744 : rw->meta->dlen = (uint)data_sz;
122 744 : }
123 :
124 : FD_PROTOTYPES_END
125 :
126 : /* Batch APIs **********************************************************
127 :
128 : These amortize I/O wait time if paired with an asynchronous database
129 : I/O engine (e.g. vinyl_io_ur). Mostly useful for reads of accounts
130 : that are not in memory cache. */
131 :
132 : FD_PROTOTYPES_BEGIN
133 :
134 : static inline ulong
135 0 : fd_accdb_batch_max( fd_accdb_user_t * accdb ) {
136 0 : return accdb->base.vt->batch_max( accdb );
137 0 : }
138 :
139 : /* fd_accdb_open_ro_multi opens a batch of accounts for read. ro[i]
140 : is initialized with an account handle. xid is the fork ID.
141 : address[i] gives the account address to query (conflicts are fine).
142 : cnt is the number of accounts to query.
143 :
144 : If account i does not exist, ro[i] gives an account with zero
145 : lamports and no data. Note that account refs over non-existent
146 : accounts must still be closed (fd_accdb_close_ref_multi).
147 :
148 : On return, the caller owns cnt accdb_ro database handles. */
149 :
150 : static inline void
151 : fd_accdb_open_ro_multi( fd_accdb_user_t * accdb,
152 : fd_accdb_ro_t * ro,
153 : fd_funk_txn_xid_t const * xid,
154 : void const * address,
155 0 : ulong cnt ) {
156 0 : accdb->base.vt->open_ro_multi( accdb, ro, xid, address, cnt );
157 0 : }
158 :
159 : /* fd_accdb_open_rw_multi opens a batch of accounts for read-write.
160 : rw[i] is either initialized with an account handle or marked as
161 : invalid (see below). xid is the fork ID. address[i] gives the
162 : account address to query (conflicts are forbidden). data_min[i]
163 : specifies the requested minimum account data byte capacity (grows
164 : account buffers if necessary). cnt is the number of accounts to
165 : query.
166 :
167 : Supported flags:
168 :
169 : CREATE: if set, and account i does not exist, rw[i] gives a valid
170 : handle with zero lamports and zero data length (but with
171 : requested buffer capacity).
172 : if not set, and account i does not exist, then sets
173 : rw[i]->ref->accdb_type=INVAL.
174 :
175 : TRUNCATE: reset the account's data length to zero (useful as a
176 : hit to the database engine to avoid copies)
177 :
178 : DONTZERO: do not zero unused account data buffer space (useful
179 : as a performance hint when the caller plans to
180 : overwrite all data bytes anyway)
181 :
182 : On return, the caller owns cnt accdb_rw database handles (some of
183 : which may be invalid). */
184 :
185 : static inline void
186 : fd_accdb_close_ro_multi( fd_accdb_user_t * accdb,
187 : fd_accdb_ro_t * ro,
188 0 : ulong cnt ) {
189 0 : accdb->base.vt->close_ref_multi( accdb, fd_type_pun( ro ), cnt );
190 0 : }
191 :
192 : FD_PROTOTYPES_END
193 :
194 : #endif /* HEADER_fd_src_flamenco_accdb_fd_accdb_sync_h */
|