Line data Source code
1 : #ifndef HEADER_fd_src_vinyl_bstream_fd_vinyl_bstream_h
2 : #define HEADER_fd_src_vinyl_bstream_fd_vinyl_bstream_h
3 :
4 : /* Client modifications to a vinyl key-val store are sequenced into
5 : total order by the vinyl tile and encoded into a stream of direct I/O
6 : friendly blocks (a "bstream"). A bstream has the strict mathematical
7 : property that a sufficient contiguous range of blocks ("the bstream's
8 : past") can be used to reconstruct the exact state of the vinyl
9 : key-val store at the bstream's "present" and then with a high
10 : probability of detecting random data corruption. Further, the
11 : bstream's past can be efficiently and continuously updated at the
12 : same time the bstream is being modified with bounded space and time
13 : overheads.
14 :
15 : To introduce concepts and give more details:
16 :
17 : - sequence space: Every byte in a bstream has a sequence number that
18 : is that byte's offset from the leading bstream byte. sequence
19 : numbers are 64-bit and wrap cyclicly (sequence wrapping is not a
20 : concern on practical timescales but the code handles it).
21 :
22 : - blocks: bstream bytes are accessed at block granularity.
23 : FD_VINYL_BSTREAM_BLOCK_SZ gives the block byte size. bstream
24 : blocks always start at FD_VINYL_BSTREAM_BLOCK_SZ multiples.
25 :
26 : - history: A bstream reader/writer maintains four block sequence
27 : numbers: seq_ancient, seq_past, seq_present, seq_future with
28 : seq_ancient <= seq_past <= seq_present <= seq_future (cyclic).
29 : These partition bstream sequence space into four regions:
30 :
31 : [seq_ancient,seq_past) (cyclic) is antiquity: these blocks have been written and forgotten (no read, no write)
32 : [seq_past, seq_present) (cyclic) is past: these blocks have been written (read only)
33 : [seq_present,seq_future) (cyclic) is present: these blocks are being written (write only)
34 : [seq_future, seq_ancient) (cyclic) is future: these blocks have not been written (no read, no write)
35 :
36 : - synchronization: The distinction between antiquity and the future
37 : is that blocks from antiquity will not be reused until the physical
38 : hardware has recorded the current location of the bstream's past.
39 :
40 : - recovery: the bstream's past is sufficient to exactly reconstruct
41 : the state of the key-val store at seq_present.
42 :
43 : - compaction: a bstream writer can cheaply prove whether or not a
44 : block is needed for recovery (blocked not needed for recovery are
45 : "garbage") and precisely track the amount of garbage in the
46 : bstream's past. The writer can use this information to decide when
47 : and how to continuously reorganize the bstream's past to yield a
48 : minimally sized past asymptotically with a bounded amount of
49 : garbage during transients ("compaction").
50 :
51 : - compression: Compaction can also statelessly re-encode the storage
52 : represetation of pairs. This will naturally compress seldom used
53 : pair data in the background while frequently used pairs will be
54 : stored uncompressed (RAW encoded) for speed.
55 :
56 : - encoding: A bstream encodes a key-val pair as follows:
57 :
58 : ----------------------------------------------------------------------- <- seq (FD_VINYL_BSTREAM_BLOCK_SZ multiple)
59 : ctl 8 type PAIR, val encoding style and val_esz ^ ^
60 : key key_sz fix sz, 8 multiple | | fd_vinyl_bstream_phdr_t
61 : val_sz 4 decoded val_sz fd_vinyl_info_t ^ | |
62 : app info INFO_SZ-4 app info v | v
63 : val val_esz encoded according to style |
64 : zero padding zpad_sz in [0,FD_VINYL_BSTREAM_BLOCK_SZ) | pair_sz (FD_VINYL_BSTREAM_BLOCK_SZ multiple)
65 : hash_trail 8 ^ |
66 : hash_blocks 8 FD_VINYL_BSTREAM_FTR_SZ v v
67 : -----------------------------------------------------------------------
68 :
69 : There is much nuance in the above:
70 :
71 : * Since sizeof(fd_vinyl_bstream_phdr_t) + FD_VINYL_BSTREAM_FTR_SZ is
72 : less than FD_VINYL_BSTREAM_BLOCK_SZ, a pair with a small enough
73 : encoded val can fit in a single block. It is not possible to
74 : encode multiple pairs in a single block though.
75 :
76 : * hash_trail covers all the pair's trailing blocks. hash_trail for
77 : a single block item is the bstream's hash seed. hash_blocks is
78 : the hash of the leading block with hash_trail as the seed.
79 :
80 : * Hashing is block oriented to create a single easily optimized
81 : case for software and hardware to target. Implementations can
82 : optimize and specialize data integrity hash functions to the case
83 : that maps a 64-bit seed and a FD_VINYL_BSTREAM_BLOCK_SZ aligned
84 : and FD_VINYL_BSTREAM_BLOCK_SZ footprint input buffer to a 64-bit
85 : output for all hashing operations.
86 :
87 : * The hashes are located at the pair end so that pairs can be
88 : streamed to storage cut-through / zero-copy style by writers with
89 : no seeking. Reading into memory can likewise be done with no
90 : intermediate copies of the pair (especially for RAW encoded
91 : pairs).
92 :
93 : * Hashing the trailing blocks and hash chaining the leading block
94 : allows updating pair metadata (e.g. renaming a pair, copying a
95 : pair, moving a pair, etc) without requiring rehashing all the
96 : data while maintaining strong data integrity protections (e.g.
97 : can detect with high probability whether the leading block has
98 : been mismatched from its trailing blocks).
99 :
100 : * Storing both hashes also allows fast high integrity bstream
101 : iteration. Specifically, iterators can fully validate small
102 : pairs and partially validate large pairs (the pair key, pair
103 : metadata and leading pair val bytes are valid and the trailing
104 : val bytes are matched to these bytes) cheaply (i.e. without
105 : needing to compute a full pair hash) with very low cost in
106 : storage or overhead on read or write.
107 :
108 : * The hashes are computed with the hash fields zeroed. The hash
109 : fields are then set when the pair is written.
110 :
111 : * This representation is cheaply relocatable (this is particularly
112 : important for compaction). For example, we could include the
113 : bstream seq in the pair header for extra redundancy (e.g. can
114 : potentially estimate bstream's past if the bstream's metadata
115 : gets corrupted) and extra data integrity checks. But then we'd
116 : have to either:
117 :
118 : - Recompute pair hashes when reorganizing the bstream's past
119 : during background compaction (which would prevent generic I/O
120 : hardware offload of bulk copies used for compaction).
121 :
122 : - Exclude seq from the block header hashing (which helps some
123 : but we'd still need to update seq in the header and thus
124 : prevent generic I/O hardware offload of bulk copies).
125 :
126 : - Keep seq constant during the compaction. This would turn seq
127 : into an indicator of when the pair was first created (or
128 : recreated if after an erase or move). Ignoring sequence wrap,
129 : this could preserve some data integrity checking (e.g. seq
130 : aligned and at or before the pair's current position) but this
131 : weakens the sync metadata redundancy benefits of including seq
132 : (can't just search for a contiguous range of well formatted
133 : blocks and use seq to get a bstream's past range estimate).
134 :
135 : - ...
136 :
137 : Instead, we go the simpler, faster and more flexible route. We
138 : omit bstream seq here from the pair. This allows pairs to be
139 : moved around in the bstream with simple bulk copies. Simpler
140 : code, more application pair metadata and faster background
141 : compaction.
142 :
143 : - control blocks: the bstream can contain control blocks to support
144 : recovery. A control block can only refer to bstream blocks before
145 : it in the bstream. Thus, they are always garbage from the point of
146 : view of compaction as they can be always be removed from the
147 : bstream's past once they are at seq_past.
148 :
149 : - zero padding: one type of control block is zero padding. These
150 : can be inserted by the bstream writer in order ensure sets of
151 : blocks are kept continguous in the underlying physical storage
152 : (e.g. making sure an encoded pair is never split across two
153 : physical volumes).
154 :
155 : - partitions: another type of control block is a partition. The
156 : bstream writer can insert partitions periodically to allow the
157 : bstream past to be quickly partitioned at object boundaries into
158 : approximately uniform slices that can be used for parallel
159 : recovery. These partitions also include the number of erases and
160 : moves that happend in the partition to aid in parallel recovery (to
161 : optionally tightly bound the size of temporary data structures at
162 : start).
163 :
164 : - hot or not: the metadata for all pairs at seq_present is always
165 : available fast O(1) to concurent vinyl users. This includes a
166 : small amount of application info (like balances, expirations, etc). */
167 :
168 : #include "../fd_vinyl_base.h"
169 :
170 : /* FD_VINYL_BSTREAM_BLOCK_SZ gives the block size in bytes of a bstream
171 : block. It is a direct I/O friendly power-of-2 (i.e. a power-of-2 >=
172 : 512). FD_VINYL_BSTEAM_BLOCK_LG_SZ gives the log2 of this. */
173 :
174 164428158 : #define FD_VINYL_BSTREAM_BLOCK_SZ (512UL)
175 0 : #define FD_VINYL_BSTREAM_BLOCK_LG_SZ (9)
176 :
177 : /* A FD_VINYL_BSTREAM_CTL_TYPE_* specifies how to interpret the next
178 : range of blocks in the bstream. A FD_VINYL_BSTREAM_CTL_STYLE_*
179 : specifies the encoding style for that range of blocks (e.g. whether
180 : or not a pair is compressed). We use a 16-bit and a 12-bit
181 : non-compact encoding respectively for these so that simple data
182 : corruption errors can be detected without doing more expensive
183 : validation first. This leaves 36 bits for ctl sz, limiting a pair's
184 : encoded val size to be in [0,2^36). The LZ4 API inexplicably uses
185 : signed 32-bit ints for buffer sizes so an encoded / decode value size
186 : is further limited to be in [0,LZ4_MAX_INPUT_SIZE) (where
187 : LZ4_MAX_INPUT_SIZE is a little under 2^31). */
188 :
189 3000000 : #define FD_VINYL_BSTREAM_CTL_TYPE_PAIR ((int)(0x9a17)) /* "pair" */
190 18 : #define FD_VINYL_BSTREAM_CTL_TYPE_SYNC ((int)(0x512c)) /* "sync" */
191 0 : #define FD_VINYL_BSTREAM_CTL_TYPE_DEAD ((int)(0xdead)) /* "dead" */
192 0 : #define FD_VINYL_BSTREAM_CTL_TYPE_MOVE ((int)(0x30c3)) /* "move" */
193 0 : #define FD_VINYL_BSTREAM_CTL_TYPE_PART ((int)(0xd121)) /* "divi"der */
194 0 : #define FD_VINYL_BSTREAM_CTL_TYPE_ZPAD (0) /* (must be zero) */
195 :
196 9000006 : #define FD_VINYL_BSTREAM_CTL_STYLE_RAW ((int)0x7a3) /* "raw" */
197 6 : #define FD_VINYL_BSTREAM_CTL_STYLE_LZ4 ((int)0x124) /* "lz4" */
198 :
199 : /* A fd_vinyl_bstream_phdr_t gives the layout of bstream pair header
200 : (e.g. ctl, type PAIR, val encoding style, val encoding size, key,
201 : decoded val size and other application info). */
202 :
203 : struct fd_vinyl_bstream_phdr {
204 : ulong ctl;
205 : fd_vinyl_key_t key;
206 : fd_vinyl_info_t info;
207 : };
208 :
209 : typedef struct fd_vinyl_bstream_phdr fd_vinyl_bstream_phdr_t;
210 :
211 : /* FD_VINYL_BSTREAM_FTR_SZ gives the number of bytes in a bstream
212 : object footer. */
213 :
214 80308878 : #define FD_VINYL_BSTREAM_FTR_SZ (2UL*sizeof(ulong))
215 :
216 : /* If pair val byte size is greater than
217 : FD_VINYL_BSTREAM_LZ4_VAL_THRESH, it is considered worth trying to
218 : encode with lz4 compression (if lz4 compression is enabled). The
219 : default below is such that, even if the val smaller than this
220 : compressed to 0 bytes, it would still require one block of bstream
221 : space. (FIXME: make this dynamically run time configured?) */
222 :
223 : #define FD_VINYL_BSTREAM_LZ4_VAL_THRESH (FD_VINYL_BSTREAM_BLOCK_SZ - sizeof(fd_vinyl_bstream_phdr_t) - FD_VINYL_BSTREAM_FTR_SZ)
224 :
225 : /* FD_VINYL_BSTREAM_*_INFO_MAX give the max app info bytes that can be
226 : stashed in the eponymous control block. */
227 :
228 18 : #define FD_VINYL_BSTREAM_SYNC_INFO_MAX (FD_VINYL_BSTREAM_BLOCK_SZ - 6UL*sizeof(ulong))
229 0 : #define FD_VINYL_BSTREAM_DEAD_INFO_MAX (FD_VINYL_BSTREAM_BLOCK_SZ - 5UL*sizeof(ulong) - sizeof(fd_vinyl_bstream_phdr_t))
230 0 : #define FD_VINYL_BSTREAM_MOVE_INFO_MAX (FD_VINYL_BSTREAM_BLOCK_SZ - 5UL*sizeof(ulong) - sizeof(fd_vinyl_bstream_phdr_t) - sizeof(fd_vinyl_key_t))
231 0 : #define FD_VINYL_BSTREAM_PART_INFO_MAX (FD_VINYL_BSTREAM_BLOCK_SZ - 8UL*sizeof(ulong))
232 :
233 : /* A fd_vinyl_bstream_block gives the binary layouts for various types
234 : of blocks. Note that direct I/O requires our memory alignments to
235 : match device alignments. Hence is this aligned
236 : FD_VINYL_BSTREAM_BLOCK_SZ in memory too. */
237 :
238 : union __attribute__((aligned(FD_VINYL_BSTREAM_BLOCK_SZ))) fd_vinyl_bstream_block {
239 :
240 : ulong ctl;
241 :
242 : fd_vinyl_bstream_phdr_t phdr; /* type PAIR, style *, sz pair val encoded sz */
243 :
244 : struct {
245 : uchar _[ FD_VINYL_BSTREAM_BLOCK_SZ - FD_VINYL_BSTREAM_FTR_SZ ];
246 : ulong hash_trail;
247 : ulong hash_blocks;
248 : } ftr;
249 :
250 : struct {
251 : ulong ctl; /* type SYNC, style 0 (ABI version), sz VAL_MAX */
252 : ulong seq_past; /* recover using blocks [seq_past,seq_present) */
253 : ulong seq_present; /* these are FD_VINYL_BSTREAM_BLOCK_SZ multiples */
254 : ulong info_sz; /* info byte size, in [0,FD_VINYL_BSTREAM_SYNC_INFO_MAX]. */
255 : uchar info[ FD_VINYL_BSTREAM_SYNC_INFO_MAX ]; /* sync info */
256 : ulong hash_trail; /* establishes bstream's hash seed */
257 : ulong hash_blocks;
258 : } sync; /* Note: this is located "outside" the bstream */
259 :
260 : struct {
261 : ulong ctl; /* type DEAD, style RAW, sz BLOCK_SZ */
262 : ulong seq; /* bstream seq num of this block */
263 : fd_vinyl_bstream_phdr_t phdr; /* pair header of the key getting erased */
264 : ulong info_sz; /* info byte size, in [0,FD_VINYL_BSTREAM_DEAD_INFO_MAX] */
265 : uchar info[ FD_VINYL_BSTREAM_DEAD_INFO_MAX ]; /* dead info */
266 : ulong hash_trail;
267 : ulong hash_blocks;
268 : } dead;
269 :
270 : struct {
271 : ulong ctl; /* type MOVE, style RAW, sz BLOCK_SZ */
272 : ulong seq; /* bstream seq num of this block */
273 : fd_vinyl_bstream_phdr_t src; /* src pair header */
274 : fd_vinyl_key_t dst; /* pair src.key renamed to pair dst or replaced pair dst */
275 : ulong info_sz; /* info byte size, in [0,FD_VINYL_BSTREAM_MOVE_INFO_MAX] */
276 : uchar info[ FD_VINYL_BSTREAM_MOVE_INFO_MAX ]; /* move info */
277 : ulong hash_trail;
278 : ulong hash_blocks;
279 : } move; /* Note: a move block is immediately followed by a matching pair */
280 :
281 : struct {
282 : ulong ctl; /* type PART, style RAW, sz BLOCK_SZ */
283 : ulong seq; /* bstream seq num of this block */
284 : ulong seq0; /* Partition starts at seq0 (at most seq, BLOCK_SZ aligned) */
285 : ulong dead_cnt; /* num dead blocks in this partition (for parallel recovery) */
286 : ulong move_cnt; /* num move blocks in this partition (for parallel recovery) */
287 : ulong info_sz; /* info byte size, in [0,FD_VINYL_BSTREAM_PART_INFO_MAX] */
288 : uchar info[ FD_VINYL_BSTREAM_PART_INFO_MAX ]; /* partition info */
289 : ulong hash_trail;
290 : ulong hash_blocks;
291 : } part;
292 :
293 : uchar zpad[ FD_VINYL_BSTREAM_BLOCK_SZ ]; /* all zeros (type, style, sz, hash_trail, hash_blocks ...) */
294 :
295 : uchar data[ FD_VINYL_BSTREAM_BLOCK_SZ ]; /* arbitrary (type, style, sz, hash_trail, hash_blocks ...) */
296 :
297 : };
298 :
299 : typedef union fd_vinyl_bstream_block fd_vinyl_bstream_block_t;
300 :
301 : FD_PROTOTYPES_BEGIN
302 :
303 : /* fd_vinyl_seq_* compare bstream sequence numbers, correctly handling
304 : wrap around. */
305 :
306 16113000 : FD_FN_CONST static inline int fd_vinyl_seq_lt( ulong a, ulong b ) { return ((long)(a-b))< 0L; }
307 9264228 : FD_FN_CONST static inline int fd_vinyl_seq_gt( ulong a, ulong b ) { return ((long)(a-b))> 0L; }
308 22702188 : FD_FN_CONST static inline int fd_vinyl_seq_le( ulong a, ulong b ) { return ((long)(a-b))<=0L; }
309 9528432 : FD_FN_CONST static inline int fd_vinyl_seq_ge( ulong a, ulong b ) { return ((long)(a-b))>=0L; }
310 9000000 : FD_FN_CONST static inline int fd_vinyl_seq_eq( ulong a, ulong b ) { return ((long)(a-b))==0L; }
311 11029572 : FD_FN_CONST static inline int fd_vinyl_seq_ne( ulong a, ulong b ) { return ((long)(a-b))!=0L; }
312 :
313 : /* fd_vinyl_bstream_ctl return the bstream control field that encodes a
314 : FD_VINYL_BSTREAM_CTL_TYPE_* type, FD_VINYL_BSTREAM_CTL_STYLE_* style,
315 : and a byte size in [0,2^36). fd_vinyl_bstream_ctl_* return the
316 : eponymous field from the given bstream ctl. */
317 :
318 : FD_FN_CONST static inline ulong
319 : fd_vinyl_bstream_ctl( int type,
320 : int style,
321 12000006 : ulong val_sz ) {
322 12000006 : return ((ulong)type) | (((ulong)style)<<16) | (val_sz<<28);
323 12000006 : }
324 :
325 35095158 : FD_FN_CONST static inline int fd_vinyl_bstream_ctl_type ( ulong ctl ) { return (int)( ctl & 65535UL); }
326 3000012 : FD_FN_CONST static inline int fd_vinyl_bstream_ctl_style( ulong ctl ) { return (int)((ctl>>16) & 4095UL); }
327 38095158 : FD_FN_CONST static inline ulong fd_vinyl_bstream_ctl_sz ( ulong ctl ) { return ctl>>28; }
328 :
329 : /* fd_vinyl_bstream_pair_sz returns the byte footprint of a pair with a
330 : val_esz encoded value byte size. Assumes val_esz in [0,2^48) which
331 : implies the worst case maximum encoded value size allowed is in
332 : [0,2^48). Returns a positive FD_VINYL_BSTREAM_BLOCK_SZ multiple. */
333 :
334 : FD_FN_CONST static inline ulong
335 53127477 : fd_vinyl_bstream_pair_sz( ulong val_esz ) {
336 53127477 : return fd_ulong_align_up( sizeof(fd_vinyl_bstream_phdr_t) + val_esz + FD_VINYL_BSTREAM_FTR_SZ, FD_VINYL_BSTREAM_BLOCK_SZ );
337 53127477 : }
338 :
339 : /* fd_vinyl_bstream_hash returns a 64-bit hash of the 64-bit seed and
340 : the sz byte buffer buf. Assumes buf is points to well aligned range
341 : of blocks stable for the duration of the call and sz is a multiple of
342 : FD_VINYL_BSTREAM_BLOCK_SZ. sz 0 returns seed. Retains no interest
343 : in buf. */
344 :
345 : FD_FN_PURE static inline ulong
346 : fd_vinyl_bstream_hash( ulong seed,
347 : fd_vinyl_bstream_block_t const * buf,
348 43653492 : ulong buf_sz ) {
349 43653492 : return FD_LIKELY( buf_sz ) ? fd_hash( seed, buf, buf_sz ) : seed;
350 43653492 : }
351 :
352 : /* fd_vinyl_bstream_block_hash initializes the hash fields of a bstream
353 : object that fits into a single block (i.e. a small val pair, sync
354 : block, a dead block, a move block or a part block). block's hash
355 : fields and any zero padding should be zero on entry. block's hash
356 : fields will be set correctly on exit. Assumes block is valid. */
357 :
358 : static inline void
359 : fd_vinyl_bstream_block_hash( ulong seed,
360 3748884 : fd_vinyl_bstream_block_t * block ) {
361 :
362 3748884 : ulong hash_trail = seed;
363 3748884 : ulong hash_blocks = fd_vinyl_bstream_hash( hash_trail, block, FD_VINYL_BSTREAM_BLOCK_SZ );
364 :
365 3748884 : block->ftr.hash_trail = hash_trail;
366 3748884 : block->ftr.hash_blocks = hash_blocks;
367 :
368 3748884 : }
369 :
370 : /* fd_vinyl_bstream_block_test returns FD_VINYL_SUCCESS if a bstream
371 : object that fits into a single bstream block (i.e. a small val pair,
372 : a sync block, a dead block, a move block or a part block) has valid
373 : data integrity hashes and FD_VINYL_ERR_CORRUPT if not. seed is the
374 : bstream's data integrity seed. Assumes block points to the valid
375 : stable location. block's hash fields will be clobbered on return
376 : (will be zero on success). */
377 :
378 : static inline int
379 : fd_vinyl_bstream_block_test( ulong seed,
380 9000006 : fd_vinyl_bstream_block_t * block ) {
381 :
382 9000006 : ulong hash_trail = block->ftr.hash_trail;
383 9000006 : ulong hash_blocks = block->ftr.hash_blocks;
384 :
385 9000006 : block->ftr.hash_trail = 0UL;
386 9000006 : block->ftr.hash_blocks = 0UL;
387 :
388 9000006 : if( FD_UNLIKELY( hash_trail != seed ) ||
389 9000006 : FD_UNLIKELY( fd_vinyl_bstream_hash( seed, block, FD_VINYL_BSTREAM_BLOCK_SZ ) != hash_blocks ) )
390 6000000 : return FD_VINYL_ERR_CORRUPT;
391 :
392 3000006 : return FD_VINYL_SUCCESS;
393 9000006 : }
394 :
395 : /* fd_vinyl_bstream_pair_zero clears the footer region and any zero
396 : padding region. */
397 :
398 : void
399 : fd_vinyl_bstream_pair_zero( fd_vinyl_bstream_block_t * phdr );
400 :
401 : /* fd_vinyl_bstream_pair_hash clears the footer region and any zero
402 : padding region of pair and then populates the hash fields
403 : appropriately. seed is the bstream data integrity seed. Assumes
404 : pair points to any appropriately sized and aligned memory region and
405 : the phdr and val fields are correctly populated (in particular,
406 : val_esz is set correctly). */
407 :
408 : void
409 : fd_vinyl_bstream_pair_hash( ulong seed,
410 : fd_vinyl_bstream_block_t * phdr );
411 :
412 : /* fd_vinyl_bstream_*_test returns NULL if bstream object at seq is
413 : well formed and an infinite lifetime human-readable cstr describing
414 : the issue detected if not. The footer has been clobbered on return
415 : (will be zero on success). seed is the bstream's data integrity
416 : seed. Assumes pair points to a valid pair_sz footprint location.
417 :
418 : For fd_vinyl_bstream_pair_test, the pair is assumed fit within the
419 : the buf_sz buffer buf, not exactly fill the buffer.
420 :
421 : fd_vinyl_bstream_pair_test_fast is the same thing but omits testing
422 : any interior blocks for use in fast iteration. hdr / ftr point
423 : locations holding the first/last block in the pair. These should
424 : point to the same location if the pair fits into a single block. */
425 :
426 : char const *
427 : fd_vinyl_bstream_pair_test( ulong seed,
428 : ulong seq,
429 : fd_vinyl_bstream_block_t * buf,
430 : ulong buf_sz );
431 :
432 : char const *
433 : fd_vinyl_bstream_pair_test_fast( ulong seed,
434 : ulong seq,
435 : fd_vinyl_bstream_block_t const * hdr,
436 : fd_vinyl_bstream_block_t * ftr );
437 :
438 : char const *
439 : fd_vinyl_bstream_dead_test( ulong seed,
440 : ulong seq,
441 : fd_vinyl_bstream_block_t * block );
442 :
443 : char const *
444 : fd_vinyl_bstream_move_test( ulong seed,
445 : ulong seq,
446 : fd_vinyl_bstream_block_t * block,
447 : fd_vinyl_bstream_block_t * dst );
448 :
449 : char const *
450 : fd_vinyl_bstream_part_test( ulong seed,
451 : ulong seq,
452 : fd_vinyl_bstream_block_t * block );
453 :
454 : char const *
455 : fd_vinyl_bstream_zpad_test( ulong seed,
456 : ulong seq,
457 : fd_vinyl_bstream_block_t * block );
458 :
459 : /* fd_vinyl_bstream_ctl_style_cstr returns an infinite lifetime human
460 : readable cstr for the given style. Return value is always non-NULL
461 : (if style is not a valid style, the string will be "unk").
462 :
463 : fd_cstr_to_vinyl_bstream_ctl_style returns the style corresponding to
464 : the given cstr. Returns -1 if cstr does not correspond to a
465 : supported style. */
466 :
467 : char const *
468 : fd_vinyl_bstream_ctl_style_cstr( int style );
469 :
470 : int
471 : fd_cstr_to_vinyl_bstream_ctl_style( char const * cstr );
472 :
473 : #if FD_HAS_AVX512 && defined(__AVX512DQ__)
474 :
475 : /* fd_vinyl_bstream_hash_batch8 does 8 fd_vinyl_bstream_hash()
476 : computations in parallel. out, buf, sz point to arrays of 8 elements
477 : respectively. */
478 :
479 : FD_FN_PURE void
480 : fd_vinyl_bstream_hash_batch8( ulong const * FD_RESTRICT seed,
481 : ulong * FD_RESTRICT out,
482 : void const * FD_RESTRICT * FD_RESTRICT buf,
483 : ulong const * FD_RESTRICT sz );
484 :
485 : #endif
486 :
487 : FD_PROTOTYPES_END
488 :
489 : #endif /* HEADER_fd_src_vinyl_bstream_fd_vinyl_bstream_h */
|