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 moment 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 reserved;
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 - in (MODIFY): requested val_max for val
140 : out: pair val (and pair info) data cache global address
141 : RELEASE - (BY_KEY) ignored, (~BY_KEY) data cache global addresses
142 : of pairs to release (i.e. echo back the array returned
143 : by acquire), (release ~BY_KEY faster)
144 : ERASE - ignored
145 : MOVE - this field is repurposed to point to the batch_cnt dst
146 : keys for the move (vinyl tile will have a read interest
147 : in this region until the request is complete)
148 : (FIXME: consider having key_gaddr be 2*batch_cnt for
149 : move, store all the keys there, and ignore this
150 : entirely ... would make sense if it is easier for
151 : store move src/dst keys interleaved)
152 : FETCH - ignored
153 : FLUSH - ignored
154 : TRY - pair val (and pair info) data cache global addresses
155 : must be a 2*batch_cnt array for try (the second half is
156 : for internal use). Note that the info region
157 : (including the val_sz for the try) might be corrupt.
158 : The pointer returned though is guaranteed to be
159 : readable out to FD_VINYL_VAL_MAX regardless val_sz.
160 : TEST - echo back the same array (with an untouched second
161 : half) from the corresponding try */
162 :
163 : ulong val_gaddr_gaddr;
164 :
165 : /* err_gaddr is typically the shared client request global address of
166 : a:
167 :
168 : schar err[ batch_cnt ]
169 :
170 : array where the results of individual batch item executions will be
171 : stored by the vinyl tile. The vinyl tile will have a write
172 : interest in this region until the request is completed. On receipt
173 : of a successful completion, the individual entries will be valid.
174 : Entries will be FD_VINYL_SUCCESS (zero) or a FD_VINYL_ERR code
175 : (negative). On receipt of a failed completion, this array is
176 : unchanged. In particular:
177 :
178 : ACQUIRE (for read)
179 :
180 : SUCCESS - acquired the corresponding pair key. The pair val
181 : and pair info can be found via the corresponding
182 : val_gaddr in the shared data cache. This location
183 : will be stable until the pair is released. info will
184 : have the current pair metadata (including the val
185 : byte size), val will have the current pair val.
186 :
187 : AGAIN - there was a conflicting acquire on pair key, try
188 : again after the conflicting acquire has been
189 : released. That is, pair key is currently
190 : acquired-for-modify (this includes pair key in the
191 : process of being created).
192 :
193 : KEY - pair key did not exist at bstream seq_present and
194 : is not in the process of being created.
195 :
196 : ACQUIRE (for modify)
197 :
198 : SUCCESS - acquired the corresponding pair key. The pair val
199 : and pair info can be found via the corresponding
200 : val_gaddr in the shared data cache. This location
201 : will be stable until the pair is released.
202 :
203 : If pair key exists and ignore was _not_ set, info
204 : will contain the current pair metadata (including the
205 : val byte size), val contain the current pair val and
206 : the val region will be sized to the greater of the
207 : current val byte size and the requested max val byte
208 : size.
209 :
210 : If pair key exists and ignore _was_ set, info will
211 : contain the _current_ pair metadata (_but_ with a val
212 : byte size of 0), val will be empty and the region
213 : will be sized to the requested max val byte size.
214 :
215 : If pair key did not exist, the pair info will be all
216 : zeros, val will be empty and the val region will be
217 : sized to the requested max val byte size.
218 :
219 : INVAL - pair key existed and exclusive was set, or the
220 : requested val_max was larger than FD_VINYL_VAL_MAX
221 :
222 : KEY - pair key did not exist and create was not set
223 :
224 : AGAIN - there was a conflicting acquire on pair, try again
225 : after conflicting acquire(s) have been released.
226 : That is, pair key is currently acquired-for-read one
227 : or more times or acquired-for-modify.
228 :
229 : RELEASE
230 :
231 : SUCCESS - released the corresponding pair key. The key-val
232 : store was updated appropriately. In particular:
233 :
234 : When releasing an acquire-for-modify _with_ modify
235 : set, the modification "happened" (i.e. is now part of
236 : the bstream's past). This includes creating or
237 : erasing a pair. The cached pair info gave the
238 : modified pair info (including the updated pair val
239 : byte size).
240 :
241 : When releasing an acquire-for-modify _without_ modify
242 : set, the modification was cancelled. If the ignore
243 : flag _was_set, the vinyl tile assumed the cached info
244 : and/or val were clobbered by the client during the
245 : acquire. If the ignore flag was _not_ set, the vinyl
246 : tile assumed the client did not alter any pair value
247 : or pair info _at_ _any_ _time_ _during_ _the_
248 : _acquire_ (such that the cached values and any
249 : speculations on those cached values during the
250 : acquire were valid). Note that when releasing an
251 : acquire-for-modify-with-ignore, the implicily
252 : clobbered the cached pair info val byte size and
253 : cached pair val for pairs that had a non-zero val
254 : size immediately before the acquire. Since the
255 : client probably didn't know if the val size was zero
256 : beforehand, it is strongly recommended that
257 : acquire-for-modify-with-ignore only be canceled via a
258 : release-with-ignore.
259 :
260 : TL;DR If client never wrote to the cached pair info
261 : or cached pair val on an
262 : acquire-for-modify-without-ignore, the modification
263 : can be cancelled fast with a release-without-modify.
264 : In all other cases, a modification should be
265 : cancelled via a release-without-modify-with-ignore.
266 :
267 : Note that release-with-modify of an acquire-for-read
268 : is considered a catastrophe (the client modified data
269 : it promised not to change and may have corrupted
270 : state of themselves, other clients and the store
271 : itself). Overrunning pair cache storage (the client
272 : set the pair info val_sz to something larger than the
273 : acquire-with-modify val_max) is also treated as a
274 : catastrophe for similar reasons.
275 :
276 : INVAL - the corresponding key (BY_KEY) / val (~BY_KEY) did
277 : not appear to be to an acquired pair
278 :
279 : ERASE
280 :
281 : SUCCESS - the corresponding key was erased
282 :
283 : KEY - the corresponding key did not exist
284 :
285 : AGAIN - corresponding key is currently acquired for something
286 : (including read, modify or create), try again after
287 : conflicting acquires have been released
288 :
289 : MOVE
290 :
291 : SUCCESS - the corresponding src_key was renamed to the
292 : corresponding dst_key. If dst_key existed before the
293 : move, it was atomically erased before renaming pair
294 : src_key. The new pair dst_key has the pair info and
295 : pair val of the old pair src_key.
296 :
297 : Note that a move from src_key to src_key is treated
298 : as a no-op that immediately succeeds (with no
299 : checking, for example, whether or not src_key even
300 : exists).
301 :
302 : KEY - the corresponding src_key did not exist
303 :
304 : AGAIN - there was at least one conflicting acquire on src_key
305 : and/or dst_key. Try again after the conflicting
306 : acquires have been released.
307 :
308 : FETCH - ignored
309 :
310 : FLUSH - ignored
311 :
312 : TRY
313 :
314 : SUCCESS - the client is clear to try a speculative
315 : (non-blocking) read of the corresponding key. The
316 : key was located in the data cache region at the given
317 : val_gaddr at the start of the try.
318 :
319 : KEY - the corresponding key did not exist to try
320 :
321 : AGAIN - the corresponding key was acquired-for-modify
322 : (includes create), try again after conflicting
323 : acquires have been released
324 :
325 : TEST
326 :
327 : SUCCESS - the speculative read was successful
328 :
329 : INVAL - the corresponding try never started (i.e. try failed
330 : with KEY or AGAIN)
331 :
332 : CORRUPT - the corresponding try failed (i.e. the pair was
333 : potentially changed during the speculation)
334 :
335 : If these are set to a positive number before sending the request,
336 : the caller can detect individual items as they finish processing
337 : (and then access the pair val and pair info via the corresponding
338 : val_gaddr on success) before receiving the completion (with some
339 : caveats for requests with redundant keys described in
340 : case_acquire). */
341 :
342 : ulong err_gaddr;
343 :
344 : /* comp_gaddr gives the shared client request gaddr of a:
345 :
346 : fd_vinyl_comp_t comp[ 1 ]
347 :
348 : or zero.
349 :
350 : If non-zero, the completion information will be written into comp
351 : (with comp->seq set to 1 last). If not, the completion will be
352 : sent to the completion queue registered to the client for this
353 : vinyl tile (and if no completion queue was registered, no
354 : completion will be sent ... which is not a recommended mode of
355 : operations).
356 :
357 : If a completion was successful, err will be FD_VINYL_SUCCESS (0),
358 : batch_cnt will match the request batch_cnt, fail_cnt will give the
359 : number of individual items in the batch that failed (in
360 : [0,batch_cnt]), and quota_rem will give the remaining client
361 : acquire quota (each successful acquire/release
362 : decrements/increments the client's remaining quota by 1 all other
363 : operations do not impact the client's quota).
364 :
365 : If a completion has an error, err will be a FD_VINYL_ERR code
366 : (negative). No processing of any items in the batch was done,
367 : batch_cnt will match the request batch_cnt, fail_cnt will be zero
368 : and quota_rem will give the remaining client acquire quota
369 : (unchanged). Reasons for a completion error are:
370 :
371 : INVAL - one or more input arrays were unmappable (i.e. not a
372 : valid global address in the shared client request memory
373 : region).
374 :
375 : FULL - client acquire quota remaining is too low to process this
376 : request fully (ACQUIRE only)
377 :
378 : FETCH and FLUSH requests do not produce completions. */
379 :
380 : ulong comp_gaddr;
381 : };
382 :
383 : typedef struct fd_vinyl_req fd_vinyl_req_t;
384 :
385 : /* A fd_vinyl_rq_t is an interprocess shared persistent SPMC queue
386 : used to communicate fd_vinyl_req_t requests from a client to vinyl
387 : tiles. It is virtually identically to fd_vinyl_cq_t but holds
388 : fd_vinyl_req_t instead of fd_vinyl_comp_t. See fd_vinyl_cq_t for
389 : concurrency and flow control details. */
390 :
391 3 : #define FD_VINYL_RQ_MAGIC (0xfd3a7352d703a6c0UL) /* fd warm snd rq magc version 0 */
392 :
393 : struct __attribute__((aligned(128))) fd_vinyl_rq_private {
394 :
395 : ulong magic; /* ==FD_VINYL_RQ_MAGIC */
396 : ulong req_cnt; /* Number of requests that can be in flight on this cq at any given time, power of 2 of least 4 */
397 : uchar _[ 112 ]; /* Padding to put seq on a separate cache line pair */
398 : ulong seq; /* Request sequence number to publish next */
399 :
400 : /* padding to 128 alignment */
401 :
402 : /* fd_vinyl_req_t req[ req_cnt ] here, seq number at idx = seq & (req_cnt-1UL) when available */
403 :
404 : /* padding to 128 alignment */
405 :
406 : };
407 :
408 : typedef struct fd_vinyl_rq_private fd_vinyl_rq_t;
409 :
410 : FD_PROTOTYPES_BEGIN
411 :
412 : /* fd_vinyl_req_{flag_*,evict_prio} extract the {given flag,eviction
413 : priority} from a fd_vinyl_req_t flags field. */
414 :
415 3000000 : FD_FN_CONST static inline int fd_vinyl_req_flag_modify( ulong flags ) { return !!(flags & FD_VINYL_REQ_FLAG_MODIFY); }
416 3000000 : FD_FN_CONST static inline int fd_vinyl_req_flag_ignore( ulong flags ) { return !!(flags & FD_VINYL_REQ_FLAG_IGNORE); }
417 3000000 : FD_FN_CONST static inline int fd_vinyl_req_flag_create( ulong flags ) { return !!(flags & FD_VINYL_REQ_FLAG_CREATE); }
418 3000000 : FD_FN_CONST static inline int fd_vinyl_req_flag_excl ( ulong flags ) { return !!(flags & FD_VINYL_REQ_FLAG_EXCL ); }
419 3000000 : FD_FN_CONST static inline int fd_vinyl_req_flag_erase ( ulong flags ) { return !!(flags & FD_VINYL_REQ_FLAG_ERASE); }
420 3000000 : FD_FN_CONST static inline int fd_vinyl_req_flag_by_key( ulong flags ) { return !!(flags & FD_VINYL_REQ_FLAG_BY_KEY); }
421 3000000 : FD_FN_CONST static inline int fd_vinyl_req_evict_prio ( ulong flags ) { return (int)((flags >> 6) & 3UL); }
422 :
423 : /* fd_vinyl_rq_{align,footprint,new,join,leave_delete} have the usual
424 : interprocess shared persistent object semantics. req_cnt is a
425 : power-of-2 of at least 4 that gives the number requests that can be
426 : in flight on this rq. */
427 :
428 : FD_FN_CONST ulong fd_vinyl_rq_align ( void );
429 : FD_FN_CONST ulong fd_vinyl_rq_footprint( ulong req_cnt );
430 : void * fd_vinyl_rq_new ( void * shmem, ulong req_cnt );
431 : fd_vinyl_rq_t * fd_vinyl_rq_join ( void * shrq );
432 : void * fd_vinyl_rq_leave ( fd_vinyl_rq_t * rq );
433 : void * fd_vinyl_rq_delete ( void * shrq );
434 :
435 : /* fd_vinyl_rq_req returns the location in the caller's address space of
436 : the rq's request array. fd_vinyl_rq_req_const is a const correct
437 : version. fd_vinyl_rq_req_cnt is the size of this array. The
438 : lifetime of the returned array is the lifetime of the local join.
439 : These assume rq is a current local join.
440 :
441 : fd_vinyl_rq_req_idx gives the array index that will cache request seq
442 : in a rq request array with req_cnt elements. */
443 :
444 : FD_FN_CONST static inline fd_vinyl_req_t *
445 112161756 : fd_vinyl_rq_req( fd_vinyl_rq_t * rq ) {
446 112161756 : return (fd_vinyl_req_t *)(rq+1);
447 112161756 : }
448 :
449 : FD_FN_CONST static inline fd_vinyl_req_t const *
450 3 : fd_vinyl_rq_req_const( fd_vinyl_rq_t const * rq ) {
451 3 : return (fd_vinyl_req_t const *)(rq+1);
452 3 : }
453 :
454 3 : FD_FN_PURE static inline ulong fd_vinyl_rq_req_cnt( fd_vinyl_rq_t const * rq ) { return rq->req_cnt; }
455 :
456 112191750 : FD_FN_CONST static inline ulong fd_vinyl_rq_req_idx( ulong seq, ulong req_cnt ) { return seq & (req_cnt-1UL); }
457 :
458 : /* fd_vinyl_rq_seq returns the position of the request producer's
459 : sequence number cursor. Specifically, at some point during the call,
460 : requests [0,seq) were published, requests (seq,ULONG_MAX] were not
461 : published, and request seq was either published, being published or
462 : not published. This is used for initial synchronization between
463 : producer and consumers. This is a compiler fence. */
464 :
465 : static inline ulong
466 3 : fd_vinyl_rq_seq( fd_vinyl_rq_t const * rq ) {
467 3 : FD_COMPILER_MFENCE();
468 3 : ulong seq = rq->seq;
469 3 : FD_COMPILER_MFENCE();
470 3 : return seq;
471 3 : }
472 :
473 : /* fd_vinyl_rq_send enqueues the given request into the given rq.
474 : Assumes rq is a current local join. This is a compiler fence. */
475 :
476 : /* FIXME: consider SIMD accelerating */
477 :
478 : static inline void
479 : fd_vinyl_rq_send( fd_vinyl_rq_t * rq,
480 : ulong req_id,
481 : ulong link_id,
482 : int type, /* In [-2^7,2^7) */
483 : ulong flags, /* In [0,2^8) */
484 : ulong batch_cnt, /* In [0,2^16) */
485 : ulong key_gaddr,
486 : ulong val_gaddr_gaddr,
487 : ulong err_gaddr,
488 112161750 : ulong comp_gaddr ) {
489 112161750 : ulong seq = rq->seq;
490 112161750 : fd_vinyl_req_t * req = fd_vinyl_rq_req( rq ) + fd_vinyl_rq_req_idx( seq, rq->req_cnt );
491 112161750 : FD_COMPILER_MFENCE();
492 112161750 : req->seq = seq - 1UL; /* Mark request seq being written */
493 112161750 : FD_COMPILER_MFENCE();
494 112161750 : req->req_id = req_id;
495 112161750 : req->link_id = link_id;
496 112161750 : req->type = (schar)type;
497 112161750 : req->flags = (uchar)flags;
498 112161750 : req->batch_cnt = (ushort)batch_cnt;
499 112161750 : req->key_gaddr = key_gaddr;
500 112161750 : req->val_gaddr_gaddr = val_gaddr_gaddr;
501 112161750 : req->err_gaddr = err_gaddr;
502 112161750 : req->comp_gaddr = comp_gaddr;
503 112161750 : FD_COMPILER_MFENCE();
504 112161750 : req->seq = seq; /* Mark request seq as written */
505 112161750 : FD_COMPILER_MFENCE();
506 112161750 : rq->seq = seq + 1UL; /* Record that requests [0,seq) are published */
507 112161750 : FD_COMPILER_MFENCE();
508 112161750 : }
509 :
510 : /* fd_vinyl_rq_recv receives request seq from the given rq. Returns 0
511 : on success, positive if request seq has not been published yet and
512 : negative if the consumer has been overrun by the producer. On
513 : return, *dst will contain the desired request on success and was
514 : clobbered otherwise. Assumes rq is a current local join and dst is
515 : valid. This is a compiler fence. */
516 :
517 : /* FIXME: consider SIMD accelerating */
518 :
519 : static inline long
520 : fd_vinyl_rq_recv( fd_vinyl_rq_t const * rq,
521 : ulong seq,
522 0 : fd_vinyl_req_t * dst ) {
523 0 : fd_vinyl_req_t const * src = fd_vinyl_rq_req_const( rq ) + fd_vinyl_rq_req_idx( seq, rq->req_cnt );
524 :
525 0 : FD_COMPILER_MFENCE();
526 0 : ulong seq0 = src->seq;
527 0 : FD_COMPILER_MFENCE();
528 0 : *dst = *src;
529 0 : FD_COMPILER_MFENCE();
530 0 : ulong seq1 = src->seq;
531 0 : FD_COMPILER_MFENCE();
532 :
533 0 : long diff0 = (long)(seq-seq0);
534 0 : long diff1 = (long)(seq-seq1);
535 0 : return fd_long_if( !diff0, diff1, diff0 );
536 0 : }
537 :
538 : FD_PROTOTYPES_END
539 :
540 : #endif /* HEADER_fd_src_vinyl_rq_fd_vinyl_rq_h */
|