Line data Source code
1 : #ifndef HEADER_fd_src_vinyl_rq_fd_vinyl_rq_h
2 : #define HEADER_fd_src_vinyl_rq_fd_vinyl_rq_h
3 :
4 : /* A fd_vinyl_req_t describes a batch request to a vinyl tile. Batch
5 : requests from a client are processed in order from that client. The
6 : individual items in a batch request can be processed in _any_ order
7 : (including concurrently). Thus ...
8 :
9 : IMPORTANT SAFETY TIP! The client promises that all items in a
10 : request are logically independent such that they can be safely
11 : processed in an arbitrary order / in parallel.
12 :
13 : The simplest way to ensure this is to keep all keys in a request
14 : unique. That being said, repeated keys in a request will generally
15 : "do the right thing" in the sense that the result can be interpreted
16 : as though each item in the request executed in some order (with some
17 : technical caveats for the advanced optimization of processing batch
18 : items before receiving a completion). Batch requests from different
19 : clients can be arbitrarily interleaved at batch request granularity.
20 :
21 : As such, a batch request executes _atomically_ relative to other
22 : requests.
23 :
24 : Note though that concurrent meta readers see individual batch items
25 : complete as they happen. Specifically, except for "move", individual
26 : items in a batch complete atomically in whatever order they were
27 : processed. (During the move of an individual item for the current
28 : implementation, there is a brief momment where a concurrent meta
29 : reader could observe both key_src and key_dst as not present.)
30 : Similarly clients doing speculative processing will see individual
31 : batch items complete atomically (including move) in whatever order
32 : they are being processed (which is the point of speculative
33 : processing). */
34 :
35 : #include "../fd_vinyl_base.h"
36 :
37 : /* FD_VINYL_REQ_{ALIGN,FOOTPRINT} give the byte alignment and footprint
38 : of a fd_vinyl_req_t. ALIGN is a reasonable power-of-2. FOOTPRINT is
39 : a multiple of ALIGN. */
40 :
41 : #define FD_VINYL_REQ_ALIGN (64UL)
42 : #define FD_VINYL_REQ_FOOTPRINT (64UL)
43 :
44 : /* FD_VINYL_REQ_TYPE_* give supported request types. Note that
45 : requests like JOIN are handled out of band because the client doesn't
46 : have a rq to send the request until it is joined. (LEAVE could be
47 : handled in band though but is handle via the same mechanism as JOIN
48 : for symmetry. SYNC and PART requests are also handled out of band as
49 : they don't pertain to individual clients.) */
50 :
51 0 : #define FD_VINYL_REQ_TYPE_ACQUIRE (0) /* Acquire the requested pairs */
52 0 : #define FD_VINYL_REQ_TYPE_RELEASE (1) /* Release the requested pairs */
53 0 : #define FD_VINYL_REQ_TYPE_ERASE (2) /* Erase the requested pairs */
54 0 : #define FD_VINYL_REQ_TYPE_MOVE (3) /* Move the requested pairs (replace if dst exists, rename if not) */
55 0 : #define FD_VINYL_REQ_TYPE_FETCH (4) /* Fetch the requested pairs into cache (does not generate a completion) */
56 0 : #define FD_VINYL_REQ_TYPE_FLUSH (5) /* Flush the requested pairs from cache (does not generate a completion) */
57 0 : #define FD_VINYL_REQ_TYPE_TRY (6) /* Start to speculatively read (non-blocking) the requested pairs */
58 0 : #define FD_VINYL_REQ_TYPE_TEST (7) /* Test for speculation success */
59 :
60 : /* FD_VINL_REQ_FLAG_* give flags that specify options for the above
61 : request types. */
62 :
63 3000000 : #define FD_VINYL_REQ_FLAG_MODIFY (1UL<<0) /* (Acquire) The client intends to modify the given pairs (info and/or val)
64 : (Release) The client modified the given pairs (info and/or val) */
65 3000000 : #define FD_VINYL_REQ_FLAG_IGNORE (1UL<<1) /* (Acquire) Ignore the existing pair val (ignored if not MODIFY),
66 : (Release) Cached pair val and/or info were clobbered (ignored if MODIFY or an acquire-for-read FIXME: have acquire-for-read with ignore set flush?) */
67 3000000 : #define FD_VINYL_REQ_FLAG_CREATE (1UL<<2) /* (Acquire) Create any pairs that do not already exist (ignored if not MODIFY) */
68 3000000 : #define FD_VINYL_REQ_FLAG_EXCL (1UL<<3) /* (Acquire) Do not modify any pairs that already exist (ignored if not MODIFY) */
69 3000000 : #define FD_VINYL_REQ_FLAG_ERASE (1UL<<4) /* (Release) Erase given pairs (ignored if not MODIFY) */
70 3000000 : #define FD_VINYL_REQ_FLAG_BY_KEY (1UL<<5) /* (Release) Use keys instead of cache val gaddrs to specify pairs to release */
71 : #define FD_VINYL_REQ_FLAG_MRU (0UL<<6) /* Make given pairs MRU (note: arb order from MRU->LRU for individual items in batch) */
72 : #define FD_VINYL_REQ_FLAG_LRU (1UL<<6) /* Make given pairs LRU (note: arb order from LRU->MRU for individual items in batch) */
73 : #define FD_VINYL_REQ_FLAG_UNC (2UL<<6) /* Do not change eviction priorities for the given pairs */
74 :
75 : /* A fd_vinyl_req_t gives the layout of a request */
76 :
77 : struct __attribute__((aligned(FD_VINYL_REQ_ALIGN))) fd_vinyl_req {
78 :
79 : ulong seq; /* Message sequence number */
80 : ulong req_id; /* Request id (identifies the request for the completion recipients) */
81 : ulong link_id; /* Link id (identifies client -> vinyl tile for request and completion recipients) */
82 : schar type; /* == FD_VINYL_REQ_TYPE_* */
83 : uchar flags; /* Bit-or of FD_VINYL_REQ_FLAG flags */
84 : ushort batch_cnt; /* Num key-val pairs in request */
85 : uint val_max; /* (acquire with modify) Max byte size pair val, in [0,FD_VINYL_VAL_MAX] */
86 :
87 : /* key_gaddr is typically the shared client request global address of
88 : a:
89 :
90 : fd_vinyl_key_t key[ batch_cnt ]
91 :
92 : array that contains the set of keys for this batch request. The
93 : vinyl tile will typically have a read interest in this region until
94 : the request is completed. In particular:
95 :
96 : ACQUIRE - keys to acquire
97 : RELEASE - (BY_KEY) keys to release, (~BY_KEY) ignored (release ~BY_KEY faster)
98 : ERASE - keys to erase
99 : FETCH - keys to fetch
100 : FLUSH - keys to flush
101 : MOVE - src keys to move
102 : TRY - keys to speculatively read
103 : TEST - ignored
104 :
105 : If there are redundant keys in a batch request, from the caller's
106 : perspective, the items will appear to executed in some serial
107 : order. E.g. in an acquire for modify, the first batch item
108 : processed for a key will result in either success or a failure and
109 : the remaining batch items for key will result in either AGAIN
110 : (because the first item acquired) or failure (because it couldn't
111 : acquire key for the same reason as first item).
112 :
113 : IMPORTANT SAFETY TIP! When doing the advanced optimization of
114 : processing batch items before receiving a completion in a batch
115 : acquire-for-read or a try, the remaining batch items for key can
116 : report success before the first batch item for key has finished
117 : reading, validating and decoding the pair. See case_acquire for
118 : more details.
119 :
120 : Note that, for FETCH, evict prio flags are ignored. The keys will
121 : always be fetched at MRU priority. */
122 :
123 : ulong key_gaddr;
124 :
125 : /* val_gaddr_gaddr is typically the shared client request global
126 : address of a:
127 :
128 : ulong val_gaddr[ batch_cnt ]
129 :
130 : array where shared data cache global addresses for pair vals should
131 : be stored on completion. The current pair info is also available
132 : to the client at this location for read / modification. The vinyl
133 : tile will have a write interest in this region until the request is
134 : complete. On receipt of a successful completion, batch items that
135 : were successfully processed will have valid entries and batch items
136 : that failed will have unchanged entries. On receipt of a failed
137 : completion, this array will be unchanged. In particular:
138 :
139 : ACQUIRE - pair val (and pair info) data cache global address
140 : RELEASE - (BY_KEY) ignored, (~BY_KEY) data cache global addresses
141 : of pairs to release (i.e. echo back the array returned
142 : by acquire), (release ~BY_KEY faster)
143 : ERASE - ignored
144 : MOVE - this field is repurposed to point to the batch_cnt dst
145 : keys for the move (vinyl tile will have a read interest
146 : in this region until the request is complete)
147 : (FIXME: consider having key_gaddr be 2*batch_cnt for
148 : move, store all the keys there, and ignore this
149 : entirely ... would make sense if it is easier for
150 : store move src/dst keys interleaved)
151 : FETCH - ignored
152 : FLUSH - ignored
153 : TRY - pair val (and pair info) data cache global addresses
154 : must be a 2*batch_cnt array for try (the second half is
155 : for internal use). Note that the info region
156 : (including the val_sz for the try) might be corrupt.
157 : The pointer returned though is guaranteed to be
158 : readable out to FD_VINYL_VAL_MAX regardless val_sz.
159 : TEST - echo back the same array (with an untouched second
160 : half) from the corresponding try */
161 :
162 : ulong val_gaddr_gaddr;
163 :
164 : /* err_gaddr is typically the shared client request global address of
165 : a:
166 :
167 : schar err[ batch_cnt ]
168 :
169 : array where the results of individual batch item executions will be
170 : stored by the vinyl tile. The vinyl tile will have a write
171 : interest in this region until the request is completed. On receipt
172 : of a successful completion, the individual entries will be valid.
173 : Entries will be FD_VINYL_SUCCESS (zero) or a FD_VINYL_ERR code
174 : (negative). On receipt of a failed completion, this array is
175 : unchanged. In particular:
176 :
177 : ACQUIRE (for read)
178 :
179 : SUCCESS - acquired the corresponding pair key. The pair val
180 : and pair info can be found via the corresponding
181 : val_gaddr in the shared data cache. This location
182 : will be stable until the pair is released. info will
183 : have the current pair metadata (including the val
184 : byte size), val will have the current pair val.
185 :
186 : AGAIN - there was a conflicting acquire on pair key, try
187 : again after the conflicting acquire has been
188 : released. That is, pair key is currently
189 : acquired-for-modify (this includes pair key in the
190 : process of being created).
191 :
192 : KEY - pair key did not exist at bstream seq_present and
193 : is not in the process of being created.
194 :
195 : ACQUIRE (for modify)
196 :
197 : SUCCESS - acquired the corresponding pair key. The pair val
198 : and pair info can be found via the corresponding
199 : val_gaddr in the shared data cache. This location
200 : will be stable until the pair is released.
201 :
202 : If pair key exists and ignore was _not_ set, info
203 : will contain the current pair metadata (including the
204 : val byte size), val contain the current pair val and
205 : the val region will be sized to the greater of the
206 : current val byte size and the requested max val byte
207 : size.
208 :
209 : If pair key exists and ignore _was_ set, info will
210 : contain the _current_ pair metadata (_but_ with a val
211 : byte size of 0), val will be empty and the region
212 : will be sized to the requested max val byte size.
213 :
214 : If pair key did not exist, the pair info will be all
215 : zeros, val will be empty and the val region will be
216 : sized to the requested max val byte size.
217 :
218 : INVAL - pair key existed and exclusive was set
219 :
220 : KEY - pair key did not exist and create was not set
221 :
222 : AGAIN - there was a conflicting acquire on pair, try again
223 : after conflicting acquire(s) have been released.
224 : That is, pair key is currently acquired-for-read one
225 : or more times or acquired-for-modify.
226 :
227 : RELEASE
228 :
229 : SUCCESS - released the corresponding pair key. The key-val
230 : store was updated appropriately. In particular:
231 :
232 : When releasing an acquire-for-modify _with_ modify
233 : set, the modification "happened" (i.e. is now part of
234 : the bstream's past). This includes creating or
235 : erasing a pair. The cached pair info gave the
236 : modified pair info (including the updated pair val
237 : byte size).
238 :
239 : When releasing an acquire-for-modify _without_ modify
240 : set, the modification was cancelled. If the ignore
241 : flag _was_set, the vinyl tile assumed the cached info
242 : and/or val were clobbered by the client during the
243 : acquire. If the ignore flag was _not_ set, the vinyl
244 : tile assumed the client did not alter any pair value
245 : or pair info _at_ _any_ _time_ _during_ _the_
246 : _acquire_ (such that the cached values and any
247 : speculations on those cached values during the
248 : acquire were valid). Note that when releasing an
249 : acquire-for-modify-with-ignore, the implicily
250 : clobbered the cached pair info val byte size and
251 : cached pair val for pairs that had a non-zero val
252 : size immediately before the acquire. Since the
253 : client probably didn't know if the val size was zero
254 : beforehand, it is strongly recommended that
255 : acquire-for-modify-with-ignore only be canceled via a
256 : release-with-ignore.
257 :
258 : TL;DR If client never wrote to the cached pair info
259 : or cached pair val on an
260 : acquire-for-modify-without-ignore, the modification
261 : can be cancelled fast with a release-without-modify.
262 : In all other cases, a modification should be
263 : cancelled via a release-without-modify-with-ignore.
264 :
265 : Note that release-with-modify of an acquire-for-read
266 : is considered a catastrophe (the client modified data
267 : it promised not to change and may have corrupted
268 : state of themselves, other clients and the store
269 : itself). Overrunning pair cache storage (the client
270 : set the pair info val_sz to something larger than the
271 : acquire-with-modify val_max) is also treated as a
272 : catastrophe for similar reasons.
273 :
274 : INVAL - the corresponding key (BY_KEY) / val (~BY_KEY) did
275 : not appear to be to an acquired pair
276 :
277 : ERASE
278 :
279 : SUCCESS - the corresponding key was erased
280 :
281 : KEY - the corresponding key did not exist
282 :
283 : AGAIN - corresponding key is currently acquired for something
284 : (including read, modify or create), try again after
285 : conflicting acquires have been released
286 :
287 : MOVE
288 :
289 : SUCCESS - the corresponding src_key was renamed to the
290 : corresponding dst_key. If dst_key existed before the
291 : move, it was atomically erased before renaming pair
292 : src_key. The new pair dst_key has the pair info and
293 : pair val of the old pair src_key.
294 :
295 : Note that a move from src_key to src_key is treated
296 : as a no-op that immediately succeeds (with no
297 : checking, for example, whether or not src_key even
298 : exists).
299 :
300 : KEY - the corresponding src_key did not exist
301 :
302 : AGAIN - there was at least one conflicting acquire on src_key
303 : and/or dst_key. Try again after the conflicting
304 : acquires have been released.
305 :
306 : FETCH - ignored
307 :
308 : FLUSH - ignored
309 :
310 : TRY
311 :
312 : SUCCESS - the client is clear to try a speculative
313 : (non-blocking) read of the corresponding key. The
314 : key was located in the data cache region at the given
315 : val_gaddr at the start of the try.
316 :
317 : KEY - the corresponding key did not exist to try
318 :
319 : AGAIN - the corresponding key was acquired-for-modify
320 : (includes create), try again after conflicting
321 : acquires have been released
322 :
323 : TEST
324 :
325 : SUCCESS - the speculative read was successful
326 :
327 : INVAL - the corresponding try never started (i.e. try failed
328 : with KEY or AGAIN)
329 :
330 : CORRUPT - the corresponding try failed (i.e. the pair was
331 : potentially changed during the speculation)
332 :
333 : If these are set to a positive number before sending the request,
334 : the caller can detect individual items as they finish processing
335 : (and then access the pair val and pair info via the corresponding
336 : val_gaddr on success) before receiving the completion (with some
337 : caveats for requests with redundant keys described in
338 : case_acquire). */
339 :
340 : ulong err_gaddr;
341 :
342 : /* comp_gaddr gives the shared client request gaddr of a:
343 :
344 : fd_vinyl_comp_t comp[ 1 ]
345 :
346 : or zero.
347 :
348 : If non-zero, the completion information will be written into comp
349 : (with comp->seq set to 1 last). If not, the completion will be
350 : sent to the completion queue registered to the client for this
351 : vinyl tile (and if no completion queue was registered, no
352 : completion will be sent ... which is not a recommended mode of
353 : operations).
354 :
355 : If a completion was successful, err will be FD_VINYL_SUCCESS (0),
356 : batch_cnt will match the request batch_cnt, fail_cnt will give the
357 : number of individual items in the batch that failed (in
358 : [0,batch_cnt]), and quota_rem will give the remaining client
359 : acquire quota (each successful acquire/release
360 : decrements/increments the client's remaining quota by 1 all other
361 : operations do not impact the client's quota).
362 :
363 : If a completion has an error, err will be a FD_VINYL_ERR code
364 : (negative). No processing of any items in the batch was done,
365 : batch_cnt will match the request batch_cnt, fail_cnt will be zero
366 : and quota_rem will give the remaining client acquire quota
367 : (unchanged). Reasons for a completion error are:
368 :
369 : INVAL - one or more input arrays were unmappable (i.e. not a
370 : valid global address in the shared client request memory
371 : region) or this was a modify request with a requested val
372 : byte size larger than FD_VINYL_VAL_MAX.
373 :
374 : FULL - client acquire quota remaining is too low to process this
375 : request fully (ACQUIRE only)
376 :
377 : FETCH and FLUSH requests do not produce completions. */
378 :
379 : ulong comp_gaddr;
380 : };
381 :
382 : typedef struct fd_vinyl_req fd_vinyl_req_t;
383 :
384 : /* A fd_vinyl_rq_t is an interprocess shared persistent SPMC queue
385 : used to communicate fd_vinyl_req_t requests from a client to vinyl
386 : tiles. It is virtually identically to fd_vinyl_cq_t but holds
387 : fd_vinyl_req_t instead of fd_vinyl_comp_t. See fd_vinyl_cq_t for
388 : concurrency and flow control details. */
389 :
390 3 : #define FD_VINYL_RQ_MAGIC (0xfd3a7352d703a6c0UL) /* fd warm snd rq magc version 0 */
391 :
392 : struct __attribute__((aligned(128))) fd_vinyl_rq_private {
393 :
394 : ulong magic; /* ==FD_VINYL_RQ_MAGIC */
395 : ulong req_cnt; /* Number of requests that can be in flight on this cq at any given time, power of 2 of least 4 */
396 : uchar _[ 112 ]; /* Padding to put seq on a separate cache line pair */
397 : ulong seq; /* Request sequence number to publish next */
398 :
399 : /* padding to 128 alignment */
400 :
401 : /* fd_vinyl_req_t req[ req_cnt ] here, seq number at idx = seq & (req_cnt-1UL) when available */
402 :
403 : /* padding to 128 alignment */
404 :
405 : };
406 :
407 : typedef struct fd_vinyl_rq_private fd_vinyl_rq_t;
408 :
409 : FD_PROTOTYPES_BEGIN
410 :
411 : /* fd_vinyl_req_{flag_*,evict_prio} extract the {given flag,eviction
412 : priority} from a fd_vinyl_req_t flags field. */
413 :
414 3000000 : FD_FN_CONST static inline int fd_vinyl_req_flag_modify( ulong flags ) { return !!(flags & FD_VINYL_REQ_FLAG_MODIFY); }
415 3000000 : FD_FN_CONST static inline int fd_vinyl_req_flag_ignore( ulong flags ) { return !!(flags & FD_VINYL_REQ_FLAG_IGNORE); }
416 3000000 : FD_FN_CONST static inline int fd_vinyl_req_flag_create( ulong flags ) { return !!(flags & FD_VINYL_REQ_FLAG_CREATE); }
417 3000000 : FD_FN_CONST static inline int fd_vinyl_req_flag_excl ( ulong flags ) { return !!(flags & FD_VINYL_REQ_FLAG_EXCL ); }
418 3000000 : FD_FN_CONST static inline int fd_vinyl_req_flag_erase ( ulong flags ) { return !!(flags & FD_VINYL_REQ_FLAG_ERASE); }
419 3000000 : FD_FN_CONST static inline int fd_vinyl_req_flag_by_key( ulong flags ) { return !!(flags & FD_VINYL_REQ_FLAG_BY_KEY); }
420 3000000 : FD_FN_CONST static inline int fd_vinyl_req_evict_prio ( ulong flags ) { return (int)((flags >> 6) & 3UL); }
421 :
422 : /* fd_vinyl_rq_{align,footprint,new,join,leave_delete} have the usual
423 : interprocess shared persistent object semantics. req_cnt is a
424 : power-of-2 of at least 4 that gives the number requests that can be
425 : in flight on this rq. */
426 :
427 : FD_FN_CONST ulong fd_vinyl_rq_align ( void );
428 : FD_FN_CONST ulong fd_vinyl_rq_footprint( ulong req_cnt );
429 : void * fd_vinyl_rq_new ( void * shmem, ulong req_cnt );
430 : fd_vinyl_rq_t * fd_vinyl_rq_join ( void * shrq );
431 : void * fd_vinyl_rq_leave ( fd_vinyl_rq_t * rq );
432 : void * fd_vinyl_rq_delete ( void * shrq );
433 :
434 : /* fd_vinyl_rq_req returns the location in the caller's address space of
435 : the rq's request array. fd_vinyl_rq_req_const is a const correct
436 : version. fd_vinyl_rq_req_cnt is the size of this array. The
437 : lifetime of the returned array is the lifetime of the local join.
438 : These assume rq is a current local join.
439 :
440 : fd_vinyl_rq_req_idx gives the array index that will cache request seq
441 : in a rq request array with req_cnt elements. */
442 :
443 : FD_FN_CONST static inline fd_vinyl_req_t *
444 73850719 : fd_vinyl_rq_req( fd_vinyl_rq_t * rq ) {
445 73850719 : return (fd_vinyl_req_t *)(rq+1);
446 73850719 : }
447 :
448 : FD_FN_CONST static inline fd_vinyl_req_t const *
449 3 : fd_vinyl_rq_req_const( fd_vinyl_rq_t const * rq ) {
450 3 : return (fd_vinyl_req_t const *)(rq+1);
451 3 : }
452 :
453 3 : FD_FN_PURE static inline ulong fd_vinyl_rq_req_cnt( fd_vinyl_rq_t const * rq ) { return rq->req_cnt; }
454 :
455 73880713 : FD_FN_CONST static inline ulong fd_vinyl_rq_req_idx( ulong seq, ulong req_cnt ) { return seq & (req_cnt-1UL); }
456 :
457 : /* fd_vinyl_rq_seq returns the position of the request producer's
458 : sequence number cursor. Specifically, at some point during the call,
459 : requests [0,seq) were published, requests (seq,ULONG_MAX] were not
460 : published, and request seq was either published, being published or
461 : not published. This is used for initial synchronization between
462 : producer and consumers. This is a compiler fence. */
463 :
464 : static inline ulong
465 3 : fd_vinyl_rq_seq( fd_vinyl_rq_t const * rq ) {
466 3 : FD_COMPILER_MFENCE();
467 3 : ulong seq = rq->seq;
468 3 : FD_COMPILER_MFENCE();
469 3 : return seq;
470 3 : }
471 :
472 : /* fd_vinyl_rq_send enqueues the given request into the given rq.
473 : Assumes rq is a current local join. This is a compiler fence. */
474 :
475 : /* FIXME: consider SIMD accelerating */
476 :
477 : static inline void
478 : fd_vinyl_rq_send( fd_vinyl_rq_t * rq,
479 : ulong req_id,
480 : ulong link_id,
481 : int type, /* In [-2^7,2^7) */
482 : ulong flags, /* In [0,2^8) */
483 : ulong batch_cnt, /* In [0,2^16) */
484 : ulong val_max,
485 : ulong key_gaddr,
486 : ulong val_gaddr_gaddr,
487 : ulong err_gaddr,
488 73850713 : ulong comp_gaddr ) {
489 73850713 : ulong seq = rq->seq;
490 73850713 : fd_vinyl_req_t * req = fd_vinyl_rq_req( rq ) + fd_vinyl_rq_req_idx( seq, rq->req_cnt );
491 73850713 : FD_COMPILER_MFENCE();
492 73850713 : req->seq = seq - 1UL; /* Mark request seq being written */
493 73850713 : FD_COMPILER_MFENCE();
494 73850713 : req->req_id = req_id;
495 73850713 : req->link_id = link_id;
496 73850713 : req->type = (schar)type;
497 73850713 : req->flags = (uchar)flags;
498 73850713 : req->batch_cnt = (ushort)batch_cnt;
499 73850713 : req->val_max = (uint)val_max;
500 73850713 : req->key_gaddr = key_gaddr;
501 73850713 : req->val_gaddr_gaddr = val_gaddr_gaddr;
502 73850713 : req->err_gaddr = err_gaddr;
503 73850713 : req->comp_gaddr = comp_gaddr;
504 73850713 : FD_COMPILER_MFENCE();
505 73850713 : req->seq = seq; /* Mark request seq as written */
506 73850713 : FD_COMPILER_MFENCE();
507 73850713 : rq->seq = seq + 1UL; /* Record that requests [0,seq) are published */
508 73850713 : FD_COMPILER_MFENCE();
509 73850713 : }
510 :
511 : /* fd_vinyl_rq_recv receives request seq from the given rq. Returns 0
512 : on success, positive if request seq has not been published yet and
513 : negative if the consumer has been overrun by the producer. On
514 : return, *dst will contain the desired request on success and was
515 : clobbered otherwise. Assumes rq is a current local join and dst is
516 : valid. This is a compiler fence. */
517 :
518 : /* FIXME: consider SIMD accelerating */
519 :
520 : static inline long
521 : fd_vinyl_rq_recv( fd_vinyl_rq_t const * rq,
522 : ulong seq,
523 0 : fd_vinyl_req_t * dst ) {
524 0 : fd_vinyl_req_t const * src = fd_vinyl_rq_req_const( rq ) + fd_vinyl_rq_req_idx( seq, rq->req_cnt );
525 :
526 0 : FD_COMPILER_MFENCE();
527 0 : ulong seq0 = src->seq;
528 0 : FD_COMPILER_MFENCE();
529 0 : *dst = *src;
530 0 : FD_COMPILER_MFENCE();
531 0 : ulong seq1 = src->seq;
532 0 : FD_COMPILER_MFENCE();
533 :
534 0 : long diff0 = (long)(seq-seq0);
535 0 : long diff1 = (long)(seq-seq1);
536 0 : return fd_long_if( !diff0, diff1, diff0 );
537 0 : }
538 :
539 : FD_PROTOTYPES_END
540 :
541 : #endif /* HEADER_fd_src_vinyl_rq_fd_vinyl_rq_h */
|