Line data Source code
1 : #ifndef HEADER_fd_src_flamenco_accdb_fd_vinyl_req_pool_h
2 : #define HEADER_fd_src_flamenco_accdb_fd_vinyl_req_pool_h
3 :
4 : /* fd_vinyl_req_pool.h provides a simple allocation policy for vinyl
5 : request metadata, and a shared memory persistent object class for
6 : convenience.
7 :
8 : This exists because metadata is not stored in-line with the shared
9 : memory request queue. Instead, the request queue holds pointers to
10 : request batches stored in another shared memory workspace.
11 :
12 : ┌───────────────┐ ┌────────────────┐ ┌───────────────┐
13 : │ vinyl_rq │ │ vinyl_req_pool │ │ vinyl_data │
14 : ├───────────────┤ ├────────────────┤ │ │
15 : │ │ │ │ ┌──┼►┌───────────┐ │
16 : │ request batch │ │ │ │ │ │ account │ │
17 : │ │ │ │ │ │ │ data │ │
18 : │ request batch ┼─┬──┼► key 0 │ │ │ │ │ │
19 : │ ... │ │ │ key 1 │ │ │ │ │ │
20 : └───────────────┘ │ │ key ... │ │ │ └───────────┘ │
21 : │ │ │ │ │ │
22 : └──┼► val_gaddr 0 ──┼─┘ │ │
23 : │ val_gaddr 1 ──┼─┐ │ │
24 : │ val_gaddr ... │ └──┼►┌───────────┐ │
25 : │ │ │ │ account │ │
26 : │ │ │ │ data │ │
27 : │ │ │ └───────────┘ │
28 : └────────────────┘ └───────────────┘
29 :
30 : The above figure illustrates the relationship between vinyl_rq and
31 : record data values. Note that the vinyl tile need not be aware of
32 : the vinyl_req_pool allocator. */
33 :
34 : #include "../../vinyl/rq/fd_vinyl_rq.h"
35 : #include "../../vinyl/cq/fd_vinyl_cq.h"
36 :
37 : /* fd_vinyl_req_pool_t stores request metadata batches.
38 :
39 : It is sized by two parameters: batch_max, the max number of request
40 : batches. And batch_key_max, the max number of keys in each request
41 : batch.
42 :
43 : Should not be declared locally (construct via fd_vinyl_req_pool_new).
44 :
45 : The req_pool itself is not safe to share across threads. However,
46 : the _gaddr() values returned are safe to share. */
47 :
48 : struct fd_vinyl_req_pool {
49 : ulong magic;
50 : ulong batch_key_max;
51 : ulong batch_max;
52 : ulong free_off;
53 : ulong free_cnt;
54 : ulong used_off;
55 :
56 : ulong key_off;
57 : ulong val_gaddr_off;
58 : ulong err_off;
59 : ulong comp_off;
60 :
61 : /* ... variable size data follows ...*/
62 : };
63 :
64 : typedef struct fd_vinyl_req_pool fd_vinyl_req_pool_t;
65 :
66 0 : #define FD_VINYL_REQ_POOL_MAGIC (0x7ecb0aa4a4730117UL) /* magic */
67 0 : #define FD_VINYL_REQ_POOL_ALIGN (128UL) /* double cache line */
68 :
69 : FD_PROTOTYPES_BEGIN
70 :
71 : /* fd_vinyl_req_pool_{align,footprint} describe a memory region suitable
72 : to hold a vinyl_req_pool object. If any footprint params are
73 : invalid, footprint silently returns 0UL.
74 : Footprint scales like O(batch_max*batch_key_max). */
75 :
76 : ulong
77 : fd_vinyl_req_pool_align( void );
78 :
79 : ulong
80 : fd_vinyl_req_pool_footprint( ulong batch_max,
81 : ulong batch_key_max );
82 :
83 : /* fd_vinyl_req_pool_new formats the memory region as a vinyl_req_pool
84 : object. shmem is assumed to be in a wksp. Returns the newly created
85 : object on success. On failure logs warning and returns NULL.
86 :
87 : Reasons for failure are: NULL shmem, misaligned shmem, invalid
88 : params, shmem not in a wksp. */
89 :
90 : void *
91 : fd_vinyl_req_pool_new( void * shmem,
92 : ulong batch_max,
93 : ulong batch_key_max );
94 :
95 : /* fd_vinyl_req_pool_join joins the caller to a vinyl_req_pool object in
96 : shared memory. Only one join should be active at a time. */
97 :
98 : fd_vinyl_req_pool_t *
99 : fd_vinyl_req_pool_join( void * shmem );
100 :
101 : /* fd_vinyl_req_pool_leave detaches the caller from a vinyl_req_pool
102 : object. (Currently a no-op, provided for readability) */
103 :
104 : void *
105 : fd_vinyl_req_pool_leave( fd_vinyl_req_pool_t * pool );
106 :
107 : /* fd_vinyl_req_pool_delete destroys a vinyl_req_pool object and returns
108 : the backing memory region back to the caller. On failure logs
109 : warning and returns NULL. */
110 :
111 : void *
112 : fd_vinyl_req_pool_delete( void * shmem );
113 :
114 : /* fd_vinyl_req_{batch_max,batch_req_max} return parameters of an
115 : existing object. */
116 :
117 : static inline ulong
118 0 : fd_vinyl_req_batch_max( fd_vinyl_req_pool_t * pool ) {
119 0 : return pool->batch_max;
120 0 : }
121 :
122 : static inline ulong
123 0 : fd_vinyl_req_batch_key_max( fd_vinyl_req_pool_t * pool ) {
124 0 : return pool->batch_key_max;
125 0 : }
126 :
127 : /* fd_vinyl_req_pool_free_batch_cnt returns the number of free batches. */
128 :
129 : static inline ulong
130 0 : fd_vinyl_req_pool_free_batch_cnt( fd_vinyl_req_pool_t * pool ) {
131 0 : return pool->free_cnt;
132 0 : }
133 :
134 : /* fd_vinyl_req_pool_acquire opens a new request batch. Returns the
135 : index of the newly required batch. Panics with FD_LOG_CRIT if no
136 : batches are free. */
137 :
138 : ulong
139 : fd_vinyl_req_pool_acquire( fd_vinyl_req_pool_t * pool );
140 :
141 : /* fd_vinyl_req_pool_release frees a request batch. Panics with
142 : FD_LOG_CRIT if this is an invalid free. */
143 :
144 : void
145 : fd_vinyl_req_pool_release( fd_vinyl_req_pool_t * pool,
146 : ulong batch_idx );
147 :
148 : /* fd_vinyl_req_batch_key returns a pointer to the array of keys for a
149 : request batch. */
150 :
151 : static inline fd_vinyl_key_t *
152 : fd_vinyl_req_batch_key( fd_vinyl_req_pool_t * pool,
153 0 : ulong batch_idx ) {
154 0 : fd_vinyl_key_t * key0 = (fd_vinyl_key_t *)( (ulong)pool + pool->key_off );
155 0 : return key0 + (batch_idx * pool->batch_key_max);
156 0 : }
157 :
158 : /* fd_vinyl_req_batch_key_gaddr returns the 'key_gaddr' paramter for a
159 : request batch. */
160 :
161 : static inline ulong
162 : fd_vinyl_req_batch_key_gaddr( fd_vinyl_req_pool_t * pool,
163 : fd_wksp_t * wksp,
164 0 : ulong batch_idx ) {
165 0 : return fd_wksp_gaddr_fast( wksp, fd_vinyl_req_batch_key( pool, batch_idx ) );
166 0 : }
167 :
168 : /* fd_vinyl_req_batch_val_gaddr returns a pointer to the array of
169 : val_gaddr values for a request batch. */
170 :
171 : static inline ulong *
172 : fd_vinyl_req_batch_val_gaddr( fd_vinyl_req_pool_t * pool,
173 0 : ulong batch_idx ) {
174 0 : ulong * val_gaddr0 = (ulong *)( (ulong)pool + pool->val_gaddr_off );
175 0 : return val_gaddr0 + (batch_idx * pool->batch_key_max);
176 0 : }
177 :
178 : /* fd_vinyl_req_batch_val_gaddr_gaddr returns the 'val_gaddr_gaddr'
179 : parameter for a request batch. */
180 :
181 : static inline ulong
182 : fd_vinyl_req_batch_val_gaddr_gaddr( fd_vinyl_req_pool_t * pool,
183 : fd_wksp_t * wksp,
184 0 : ulong batch_idx ) {
185 0 : return fd_wksp_gaddr_fast( wksp, fd_vinyl_req_batch_val_gaddr( pool, batch_idx ) );
186 0 : }
187 :
188 : /* fd_vinyl_req_batch_err returns a pointer to the error codes for a
189 : request batch. */
190 :
191 : static inline schar *
192 : fd_vinyl_req_batch_err( fd_vinyl_req_pool_t * pool,
193 0 : ulong batch_idx ) {
194 0 : schar * err0 = (schar *)( (ulong)pool + pool->err_off );
195 0 : return err0 + (batch_idx * pool->batch_key_max);
196 0 : }
197 :
198 : /* fd_vinyl_req_batch_err_gaddr returns the 'err_gaddr' parameter for a
199 : request batch. */
200 :
201 : static inline ulong
202 : fd_vinyl_req_batch_err_gaddr( fd_vinyl_req_pool_t * pool,
203 : fd_wksp_t * wksp,
204 0 : ulong batch_idx ) {
205 0 : return fd_wksp_gaddr_fast( wksp, fd_vinyl_req_batch_err( pool, batch_idx ) );
206 0 : }
207 :
208 : /* fd_vinyl_req_batch_comp returns a pointer to the completion object of
209 : a request batch. */
210 :
211 : static inline fd_vinyl_comp_t *
212 : fd_vinyl_req_batch_comp( fd_vinyl_req_pool_t * pool,
213 0 : ulong batch_idx ) {
214 0 : fd_vinyl_comp_t * comp0 = (fd_vinyl_comp_t *)( (ulong)pool + pool->comp_off );
215 0 : return comp0 + batch_idx;
216 0 : }
217 :
218 : /* fd_vinyl_req_batch_comp_gaddr returns the 'comp_gaddr' parameter for
219 : a request batch. */
220 :
221 : static inline ulong
222 : fd_vinyl_req_batch_comp_gaddr( fd_vinyl_req_pool_t * pool,
223 : fd_wksp_t * wksp,
224 0 : ulong batch_idx ) {
225 0 : return fd_wksp_gaddr_fast( wksp, fd_vinyl_req_batch_comp( pool, batch_idx ) );
226 0 : }
227 :
228 : /* fd_vinyl_rq_send_batch is syntax sugar for fd_vinyl_rq_send with a
229 : req_pool-provided request batch. */
230 :
231 : static inline void
232 : fd_vinyl_req_send_batch( fd_vinyl_rq_t * rq,
233 : fd_vinyl_req_pool_t * req_pool,
234 : fd_wksp_t * req_pool_wksp,
235 : ulong req_id,
236 : ulong link_id,
237 : int type,
238 : ulong flags,
239 : ulong batch_idx,
240 : ulong batch_cnt,
241 0 : ulong val_max ) {
242 0 : ulong key_gaddr = fd_vinyl_req_batch_key_gaddr ( req_pool, req_pool_wksp, batch_idx );
243 0 : ulong val_gaddr_gaddr = fd_vinyl_req_batch_val_gaddr_gaddr( req_pool, req_pool_wksp, batch_idx );
244 0 : ulong err_gaddr = fd_vinyl_req_batch_err_gaddr ( req_pool, req_pool_wksp, batch_idx );
245 0 : ulong comp_gaddr = fd_vinyl_req_batch_comp_gaddr ( req_pool, req_pool_wksp, batch_idx );
246 0 : fd_vinyl_rq_send( rq, req_id, link_id, type, flags, batch_cnt, val_max, key_gaddr, val_gaddr_gaddr, err_gaddr, comp_gaddr );
247 0 : }
248 :
249 : FD_PROTOTYPES_END
250 :
251 : #endif /* HEADER_fd_src_flamenco_accdb_fd_vinyl_req_pool_h */
|