Line data Source code
1 : #ifndef HEADER_fd_src_vinyl_data_fd_vinyl_data_h
2 : #define HEADER_fd_src_vinyl_data_fd_vinyl_data_h
3 :
4 : /* fd_vinyl_data provides a data structure suitable for in-memory
5 : caching extremely of large amounts of variable sized pairs in memory.
6 : The memory layouts are such that cached pairs can be zero copy
7 : lockfree operated on by multiple threads in other address spaces and
8 : async direct I/O hardware concurrently.
9 :
10 : Note that, though pairs are cached in a shared memory region, this is
11 : not a persistent or concurrent datastructure. Specifically, only the
12 : vinyl tile can allocate or free objects from it and then can do only
13 : sequentially.
14 :
15 : Notes:
16 :
17 : - The shared memory region is divided into a fixed number of fixed
18 : sized volumes (similar to fd_groove).
19 : - Volumes flexibly store data objects.
20 : - Volumes not in use are stored on a free volume stack.
21 : - The size of a data object is determined by the object's size class.
22 : - A data object can either be an allocation (i.e. a cached pair val
23 : that fits in that object's sizeclass) or a superblock (a collection
24 : of smaller data objects from the same sizeclass).
25 :
26 : The algorithms that manage the allocations are virtually identical to
27 : fd_groove and fd_alloc. But they have been simplified, customized
28 : and optimized for this use case (e.g. minimal need for address
29 : translation, no need for atomic operations, no need for concurrency
30 : group optimizations, no need to layout cache for concurrent access,
31 : much more fine grained size classes for minimal data store overheads,
32 : etc). This also does extensive (and compile time configurable)
33 : memory data integrity continuously to help catch memory corruption
34 : (either due to hardware failures, buggy usage or malicious usage).
35 :
36 : I/O alignment requirements quantize the data cache footprint of a
37 : val_sz pair to BLOCK_SZ+align_up(pair_sz(val_sz),BLOCK_SZ). This
38 : unavoidable quantization dominates allocation footprint efficiency
39 : for the smallest values (e.g. a val_sz 1 pair will occupy 2 blocks
40 : for the I/O alignment requirements and metadata). This is negligible
41 : for large pairs (e.g. ~0.0024% for a VAL_MAX ~ 10 MiB val).
42 :
43 : Rounding an allocation to the smallest compatible size class adds no
44 : additional overhead for smallest sizes (every possible quantization
45 : of a val_sz less then ~4-8 KiB has a dedicated sizeclass). For
46 : object sizes << VAL_MAX, the worst case overhead is better than ~2%.
47 : For the object sizes ~ VAL_MAX, if the volume size is ~O(1) VAL_MAX,
48 : volume divisibility starts to impact this overhead. It still less
49 : than ~20% for the current config (and such sizes should be rare in
50 : the practical usage). This effect can eliminated by using volume
51 : sizes much larger than VAL_MAX (at the expense of creating a deeper
52 : sizeclass nesting).
53 :
54 : The packing of objects into nested superblocks also incurs a small
55 : amount of additional overhead. The smallest footprint object (2
56 : blocks or 256B) will be in a leaf superblock with 64 objects. The
57 : leaf superblock overhead (128B) amortized over these 64 objects is
58 : thus 2 bytes per object. This leaf superblock will be nested in a
59 : larger superblock with 2 leaf superblocks. With 128B additional
60 : overhead amortized over 128 objects, this yields 1 more byte overhead
61 : per object. And so forth. For this sizeclass, the overall
62 : superblock overhead converges to <~4 bytes per object absolute or
63 : <~1.5% relative. This is a rough relative upper bound for all
64 : sizeclasses. Specifically, for leaf superblocks with less than 64
65 : objects, there is more absolute superblock overhead per object but
66 : the object itself is large enough to compensate. And for objects in
67 : large superblocks, the objects more than large enough to compensate.
68 :
69 : The allocator will also implicitly adaptively preallocate space for
70 : frequently used sizeclasses to speed up allocations. For
71 : asymptotically large data caches relative to the worst case object
72 : sizes, the amount of preallocation is very small.
73 :
74 : TL;DR Allocator footprint overhead is the unavoidable BLOCK_SZ
75 : quantization plus a couple percent typically. */
76 :
77 : #include "../io/fd_vinyl_io.h"
78 :
79 4417008 : #define FD_VINYL_DATA_VOL_FOOTPRINT (41944192UL) /* autogenerated */
80 39142140 : #define FD_VINYL_DATA_SZC_CNT (83UL) /* autogenerated */
81 31457454 : #define FD_VINYL_DATA_SZC_ITER_MAX (7UL) /* autogenerated */
82 :
83 : /* fd_vinyl_data_szc **************************************************/
84 :
85 : struct __attribute__((aligned(8))) fd_vinyl_data_szc_cfg {
86 : uint val_max; /* max pair val byte size that can be stored in an object in this size class.
87 : The object is aligned in memory with FD_VINYL_BSTREAM_BLOCK_SZ alignment and with a footprint of:
88 : FD_VINYL_BSTREAM_BLOCK_SZ + sizeof(fd_vinyl_bstream_phdr_t) + val_max + FD_VINYL_BSTREAM_FTR_SZ
89 : The footprint is a FD_VINYL_BSTREAM_BLOCK_SZ multiple. */
90 : ushort obj_cnt; /* ==num objects in the containing superblock, in [2,64] */
91 : ushort parent_szc; /* size class of the superblock that contains objects of this size class,
92 : FD_VINYL_DATA_SZC_CNT indicates superblocks for objects of this size class fill an entire volume,
93 : (the superblock footprint is FD_VINYL_BSTREAM_BLOCK_SZ + obj_cnt*obj_footprint) */
94 : };
95 :
96 : typedef struct fd_vinyl_data_szc_cfg fd_vinyl_data_szc_cfg_t;
97 :
98 : FD_PROTOTYPES_BEGIN
99 :
100 : /* fd_vinyl_data_szc_cfg describes the sizeclasses used by the data
101 : cache. Indexed [0,FD_VINYL_DATA_SZC_CNT). */
102 :
103 : extern fd_vinyl_data_szc_cfg_t const fd_vinyl_data_szc_cfg[ FD_VINYL_DATA_SZC_CNT ];
104 :
105 : /* fd_vinyl_data_szc_obj_footprint returns the in-memory footprint for
106 : an object with the given size class.
107 :
108 : fd_vinyl_data_szc_val_max returns the largest pair val that can be
109 : cached in an object with the given size class. Assumes szc is in
110 : [O,FD_VINYL_DATA_SZC_CNT). Return will be in
111 : [0,cfg(SZC_CNT-1).val_max].
112 :
113 : fd_vinyl_data_szc returns the tightest fitting size class that can
114 : cache a pair val with a maximum size of val_max. Assumes val_max is
115 : in [0,szc.cfg(SZC_CNT-1.val_max]. Return will be in
116 : [0,FD_VINYL_DATA_SZC_CNT). The returned size class is typically able
117 : to hold a val_max ~1-2% larger than the given val_max.
118 :
119 : Note that the size classes are configured such that, given val_sz in
120 : [0,FD_VINYL_VAL_MAX]:
121 :
122 : fd_vinyl_data_szc_val_max( fd_vinyl_data_szc( val_sz ) ) <= FD_VINYL_VAL_MAX.
123 :
124 : where equality is achieved when val_sz==FD_VINYL_VAL_MAX.
125 :
126 : FIXME: should these be FD_FN_CONST (szc_cfg is const)? */
127 :
128 : FD_FN_PURE static inline ulong
129 5914674 : fd_vinyl_data_szc_obj_footprint( ulong szc ) {
130 5914674 : return FD_VINYL_BSTREAM_BLOCK_SZ +
131 5914674 : sizeof(fd_vinyl_bstream_phdr_t) + (ulong)fd_vinyl_data_szc_cfg[ szc ].val_max + FD_VINYL_BSTREAM_FTR_SZ;
132 5914674 : }
133 :
134 : FD_FN_PURE static inline ulong
135 14899077 : fd_vinyl_data_szc_val_max( ulong szc ) {
136 14899077 : return (ulong)fd_vinyl_data_szc_cfg[ szc ].val_max;
137 14899077 : }
138 :
139 : FD_FN_PURE static inline ulong
140 31457454 : fd_vinyl_data_szc( ulong val_max ) {
141 :
142 31457454 : ulong l = 0UL;
143 31457454 : ulong h = FD_VINYL_DATA_SZC_CNT-1UL;
144 :
145 251659632 : for( ulong rem=FD_VINYL_DATA_SZC_ITER_MAX; rem; rem-- ) {
146 :
147 : /* At this point, szc in [0,l) aren't suitable, szc in [h,CNT) are
148 : suitable and szc in [l,h) are untested. See fd_alloc for more
149 : detail on using fixed count loop. */
150 :
151 220202178 : ulong m = (l+h) >> 1;
152 220202178 : int c = (((ulong)fd_vinyl_data_szc_cfg[ m ].val_max) >= val_max);
153 220202178 : l = fd_ulong_if( c, l, m+1UL );
154 220202178 : h = fd_ulong_if( c, m, h );
155 :
156 220202178 : }
157 :
158 31457454 : return l;
159 31457454 : }
160 :
161 : FD_PROTOTYPES_END
162 :
163 : /* fd_vinyl_data_obj **************************************************/
164 :
165 1050 : #define FD_VINYL_DATA_OBJ_TYPE_FREEVOL (0xf7eef7eef7eef7eeUL) /* free, object is a free volume */
166 1456068 : #define FD_VINYL_DATA_OBJ_TYPE_ALLOC (0xa11ca11ca11ca11cUL) /* allc, object is an allocation */
167 552570 : #define FD_VINYL_DATA_OBJ_TYPE_SUPERBLOCK (0x59e759e759e759e7UL) /* sper, object is a superblock */
168 :
169 : #define FD_VINYL_DATA_OBJ_GUARD_SZ (FD_VINYL_BSTREAM_BLOCK_SZ - sizeof(fd_vinyl_io_rd_t) - 8UL*sizeof(ulong))
170 :
171 : struct fd_vinyl_data_obj;
172 : typedef struct fd_vinyl_data_obj fd_vinyl_data_obj_t;
173 :
174 : struct __attribute__((aligned(FD_VINYL_BSTREAM_BLOCK_SZ))) fd_vinyl_data_obj {
175 :
176 : /* type gives the object type. A FD_VINYL_DATA_OBJ_TYPE_*.
177 :
178 : For type SUPERBLOCK objects, child_szc gives the size class of the
179 : objects contained in this superblock. In
180 : [0,FD_VINYL_DATA_SZC_CNT). Ignored for other types of objects.
181 :
182 : For type SUPERBLOCK and type ALLOC objects, szc gives the size
183 : class of the object. In [0,FD_VINYL_DATA_SZC_CNT]. Values less
184 : then SZC_CNT indicate an object contained in a superblock. Equal
185 : to SZC_CNT indicates an object that fills an entire volume. For
186 : other types of objects, ignored.
187 :
188 : For objects contained in a parent superblock, idx gives the index
189 : of the object in its parent, in [0,szc.obj_cnt). For objects that
190 : fill an entire volume, idx gives the data volume index, in
191 : [0,vol_cnt).
192 :
193 : For type SUPERBLOCK objects, free_blocks gives a bit field
194 : identifying which blocks are free. Ignored for other types of
195 : objects.
196 :
197 : For inactive type SUPERBLOCK objects, next_off gives the byte
198 : offset from laddr0 of the next inactive superblock and 0UL if no
199 : more inactive superblocks. next_off is ignored in other
200 : circumstances (but see note about pending I/O ops). Note that this
201 : implies laddr0 must less than the local address of vol (such that
202 : data gaddr==0 never points to an object). Note also that, if
203 : laddr0 is 0, next_off will be just a pointer in the local address
204 : space.
205 :
206 : Note that I/O acceleration may require memory alignment and I/O
207 : device alignment to match. So we need to put all the object
208 : allocator data its own block. This can leave a lot of extra space.
209 : We put this space up front in the block to that it can act as a
210 : guard region for whatever preceeds it (applications could even use
211 : this guard region to stash extra info but this is not recommended
212 : because of false sharing conflicts in might induce between
213 : different threads using adjacent in memory objects). Likewise,
214 : because we have all this space from block quantization, we don't
215 : try to be hyperefficient with the packing (like we do for, say,
216 : fd_alloc). */
217 :
218 : # if 0 /* Note: with BLOCK_SZ==128, GUARD_SZ=0 so there's no guard field due to language limitations */
219 : uchar guard[ FD_VINYL_DATA_OBJ_GUARD_SZ ];
220 : # endif
221 :
222 : /* rd on its own cache line */
223 :
224 : fd_vinyl_io_rd_t rd[1]; /* rd: ctx is element idx */
225 :
226 : /* allocator metadata on its own cache line */
227 :
228 : ulong unused[1]; /* unused space */
229 : schar * rd_err; /* rd: client req_err (or dummy location if no client req_err) */
230 : short rd_active; /* rd: is a read in progess on this obj */
231 : ushort _unused; /* unused space */
232 : ushort szc; /* data: allocation size class */
233 : ushort child_szc; /* data: (superblock) contains allocations of this sizeclass */
234 : ulong line_idx; /* vinyl line_idx that is responsible for this object, in [0,line_cnt), ignored if not type alloc */
235 : ulong type; /* data: allocation type (alloc or superblock) */
236 : ulong idx; /* data: (alloc or superblock) index of this allocation in its parent superblock, (vol) vol idx */
237 : ulong free_blocks; /* data: (superblock) bit field free allocations */
238 : ulong next_off; /* data: (inactive superblock) pointer to next inactive superblock or 0 last */
239 :
240 : /* This point is FD_VINYL_BSTREAM_BLOCK_SZ aligned */
241 :
242 : /* Space for sizeof(fd_vinyl_bstream_phdr_t) + fd_vinyl_data_szc_cfg[szc].val_max + FD_VINYL_BSTREAM_FTR_SZ
243 :
244 : Note that is is a FD_VINYL_BSTREAM_BLOCK_SZ multiple so that the
245 : entire region starting from phdr can submitted zero copy for
246 : streaming to hardware async direct I/O friendly. */
247 :
248 : /* This point is FD_VINYL_BSTREAM_BLOCK_SZ aligned */
249 :
250 : /* There is an implied FD_VINYL_DATA_OBJ_GUARD_SZ region here as per
251 : note above. It is not considered part of _this_ data_obj_t though. */
252 :
253 : };
254 :
255 : FD_PROTOTYPES_BEGIN
256 :
257 : /* fd_vinyl_data_obj_* returns a pointer to the eponymous field in
258 : the given data object. Assumes obj is valid. Returns value for
259 : fd_vinyl_data_obj_phdr will be FD_VINYL_BSTREAM_BLOCK_SZ aligned.
260 : fd_vinyl_data_* mirror the above but they take the value region as
261 : input. */
262 :
263 : FD_FN_CONST static inline fd_vinyl_bstream_phdr_t *
264 3000000 : fd_vinyl_data_obj_phdr( fd_vinyl_data_obj_t const * obj ) {
265 3000000 : return (fd_vinyl_bstream_phdr_t *)((ulong)obj + sizeof(fd_vinyl_data_obj_t));
266 3000000 : }
267 :
268 : FD_FN_CONST static inline fd_vinyl_key_t *
269 3000000 : fd_vinyl_data_obj_key( fd_vinyl_data_obj_t const * obj ) {
270 3000000 : return (fd_vinyl_key_t *)((ulong)obj + sizeof(fd_vinyl_data_obj_t) + sizeof(ulong));
271 3000000 : }
272 :
273 : FD_FN_CONST static inline fd_vinyl_info_t *
274 6000000 : fd_vinyl_data_obj_info( fd_vinyl_data_obj_t const * obj ) {
275 6000000 : return (fd_vinyl_info_t *)((ulong)obj + sizeof(fd_vinyl_data_obj_t) + sizeof(ulong) + sizeof(fd_vinyl_key_t));
276 6000000 : }
277 :
278 : FD_FN_CONST static inline void *
279 3000000 : fd_vinyl_data_obj_val( fd_vinyl_data_obj_t const * obj ) {
280 3000000 : return (void *)((ulong)obj + sizeof(fd_vinyl_data_obj_t) + sizeof(fd_vinyl_bstream_phdr_t));
281 3000000 : }
282 :
283 : FD_FN_PURE static inline ulong
284 3000000 : fd_vinyl_data_obj_val_sz( fd_vinyl_data_obj_t const * obj ) {
285 3000000 : return (ulong)fd_vinyl_data_obj_info( obj )->val_sz;
286 3000000 : }
287 :
288 : FD_FN_PURE static inline ulong
289 3000000 : fd_vinyl_data_obj_val_max( fd_vinyl_data_obj_t const * obj ) {
290 3000000 : return fd_vinyl_data_szc_val_max( (ulong)obj->szc );
291 3000000 : }
292 :
293 : FD_FN_CONST static inline fd_vinyl_data_obj_t *
294 6000000 : fd_vinyl_data_obj( void const * val ) {
295 6000000 : return (fd_vinyl_data_obj_t *)((ulong)val - sizeof(fd_vinyl_bstream_phdr_t) - sizeof(fd_vinyl_data_obj_t));
296 6000000 : }
297 :
298 : FD_FN_CONST static inline fd_vinyl_bstream_phdr_t *
299 3000000 : fd_vinyl_data_phdr( void const * val ) {
300 3000000 : return (fd_vinyl_bstream_phdr_t *)((ulong)val - sizeof(fd_vinyl_bstream_phdr_t));
301 3000000 : }
302 :
303 : FD_FN_CONST static inline fd_vinyl_key_t *
304 3000000 : fd_vinyl_data_key( void const * val ) {
305 3000000 : return (fd_vinyl_key_t *)((ulong)val - sizeof(fd_vinyl_info_t) - sizeof(fd_vinyl_key_t));
306 3000000 : }
307 :
308 : FD_FN_CONST static inline fd_vinyl_info_t *
309 6000000 : fd_vinyl_data_info( void const * val ) {
310 6000000 : return (fd_vinyl_info_t *)((ulong)val - sizeof(fd_vinyl_info_t));
311 6000000 : }
312 :
313 : FD_FN_PURE static inline ulong
314 3000000 : fd_vinyl_data_val_sz( void const * val ) {
315 3000000 : return (ulong)fd_vinyl_data_info( val )->val_sz;
316 3000000 : }
317 :
318 : FD_FN_PURE static inline ulong
319 3000000 : fd_vinyl_data_val_max( void const * val ) {
320 3000000 : return fd_vinyl_data_szc_val_max( (ulong)fd_vinyl_data_obj( val )->szc );
321 3000000 : }
322 :
323 : FD_PROTOTYPES_END
324 :
325 : /* fd_vinyl_data_vol **************************************************/
326 :
327 : struct fd_vinyl_data_vol {
328 : fd_vinyl_data_obj_t obj[1];
329 : uchar data[ FD_VINYL_DATA_VOL_FOOTPRINT - sizeof(fd_vinyl_data_obj_t) ];
330 : };
331 :
332 : typedef struct fd_vinyl_data_vol fd_vinyl_data_vol_t;
333 :
334 : /* fd_vinyl_data ******************************************************/
335 :
336 : #define FD_VINYL_DATA_ALIGN (128UL)
337 : #define FD_VINYL_DATA_FOOTPRINT sizeof(fd_vinyl_data_t)
338 :
339 : struct __attribute((aligned(FD_VINYL_DATA_ALIGN))) fd_vinyl_data {
340 : void * shmem; /* Raw shared memory region */
341 : ulong shmem_sz; /* Raw shared memory region size */
342 : void * laddr0; /* Location where gaddr 0 points in the local address space
343 : (FD_VINYL_BSTREAM_BLOCK_SZ aligned) */
344 : fd_vinyl_data_vol_t * vol; /* Vols, indexed [0,vol_cnt), in raw shared memory region */
345 : ulong vol_cnt; /* Num vols, in [0,FD_VINYL_DATA_VOL_MAX) */
346 : ulong vol_idx_free; /* Idx of first free volume if in [0,vol_cnt), no free volumes o.w. */
347 : struct {
348 : fd_vinyl_data_obj_t * active; /* active superblock for this size class */
349 : fd_vinyl_data_obj_t * inactive_top; /* top of the inactive superblock stack for this size class */
350 : } superblock[ FD_VINYL_DATA_SZC_CNT ];
351 : };
352 :
353 : typedef struct fd_vinyl_data fd_vinyl_data_t;
354 :
355 : FD_PROTOTYPES_BEGIN
356 :
357 : /* fd_vinyl_data_{align,footprint} return the alignment and footprint
358 : needed for a local memory region to hold the state of a data cache.
359 : align will be a power of 2 and footprint will be a multiple of align.
360 : Matches FD_VINYL_DATA_{ALIGN,FOOTPRINT}. */
361 :
362 : FD_FN_CONST ulong fd_vinyl_data_align ( void );
363 : FD_FN_CONST ulong fd_vinyl_data_footprint( void );
364 :
365 : /* fd_vinyl_data_init formats a suitable local memory region lmem and an
366 : arbitrary shared memory region shmem with byte size shmem_sz as a
367 : vinyl data cache. laddr0 gives the location in the caller's local
368 : address space that corresponds to data object global address 0. It
369 : should be FD_VINYL_BSTREAM_BLOCK_SZ aligned and before shmem. E.g.
370 : laddr0==NULL could be used when the data objects aren't shared with
371 : threads in different processes while laddr0==wksp could be used for
372 : data objects that are shared and backed by a wksp.
373 :
374 : IMPORTANT SAFETY TIP! This does _not_ do the initial formatting of
375 : the shmem region into free data volumes (e.g. the caller can use the
376 : data shmem region as a scratch during thread parallel resume and then
377 : format it appropriately). The caller is responsible for calling
378 : fd_vinyl_data_reset before using data as an object store.
379 :
380 : Returns a handle to the data cache on success (data cache owns the
381 : memory regions) and NULL on failure (bad lmem, bad shmem, too small
382 : size ... logs details, no ownership changes). */
383 :
384 : fd_vinyl_data_t *
385 : fd_vinyl_data_init( void * lmem,
386 : void * shmem,
387 : ulong shmem_sz,
388 : void * laddr0 );
389 :
390 : /* fd_vinyl_data_fini stops using lmem and shmem as a data cache.
391 : Returns lmem on success and NULL on failure (logs details). */
392 :
393 : void *
394 : fd_vinyl_data_fini( fd_vinyl_data_t * data );
395 :
396 : /* fd_vinyl_data_{laddr0,shmem,shmem_sz} return the address translation
397 : and shared memory region used by the data cache. */
398 :
399 3 : FD_FN_PURE static inline void * fd_vinyl_data_laddr0 ( fd_vinyl_data_t const * data ) { return (void *)data->laddr0; }
400 3 : FD_FN_PURE static inline void * fd_vinyl_data_shmem ( fd_vinyl_data_t const * data ) { return (void *)data->shmem; }
401 3 : FD_FN_PURE static inline ulong fd_vinyl_data_shmem_sz( fd_vinyl_data_t const * data ) { return data->shmem_sz; }
402 :
403 : /* fd_vinyl_data_is_valid_obj returns 1 if laddr appears to point to
404 : a valid data object and 0 if not. vol points to data volume 0 in the
405 : local address space and vol_cnt is the number of data volumes. */
406 :
407 : FD_FN_PURE static inline int
408 : fd_vinyl_data_is_valid_obj( void const * laddr,
409 : fd_vinyl_data_vol_t const * vol,
410 4252611 : ulong vol_cnt ) {
411 :
412 4252611 : ulong vol_idx = ((ulong)laddr - (ulong)vol) / FD_VINYL_DATA_VOL_FOOTPRINT;
413 :
414 4252611 : if( FD_UNLIKELY( !( ((ulong)vol<=(ulong)laddr) &
415 4252611 : (vol_idx<vol_cnt) &
416 4252611 : fd_ulong_is_aligned( (ulong)laddr, FD_VINYL_BSTREAM_BLOCK_SZ ) ) ) ) return 0;
417 :
418 : /* At this point, laddr seems to be properly aligned and in volume
419 : vol_idx. We are safe to read the type and sizeclass. */
420 :
421 4252611 : fd_vinyl_data_obj_t const * obj = (fd_vinyl_data_obj_t const *)laddr;
422 4252611 : ulong szc = (ulong)obj->szc;
423 :
424 4252611 : if( FD_UNLIKELY( !((obj->type==FD_VINYL_DATA_OBJ_TYPE_ALLOC) & (szc<FD_VINYL_DATA_SZC_CNT)) ) ) return 0;
425 :
426 : /* At this point, laddr seems to contain an allocation of sizeclass
427 : szc. Make sure the object idx seems to be valid and the object is
428 : contained entirely within volume vol_idx. */
429 :
430 2851011 : ulong end = (ulong)laddr + fd_vinyl_data_szc_obj_footprint( szc );
431 :
432 2851011 : if( FD_UNLIKELY( !((obj->idx<(ulong)fd_vinyl_data_szc_cfg[ szc ].obj_cnt) & (end<=(ulong)&vol[vol_idx+1UL])) ) ) return 0;
433 :
434 2851011 : return 1;
435 2851011 : }
436 :
437 : /* fd_vinyl_data_alloc acquires an object of sizeclass szc from the data
438 : cache. Returns a pointer to the object on success and NULL if there
439 : is no space available in the data. Will FD_LOG_CRIT if anything
440 : wonky is detected (bad, memory corruption, etc). */
441 :
442 : fd_vinyl_data_obj_t *
443 : fd_vinyl_data_alloc( fd_vinyl_data_t * data,
444 : ulong szc );
445 :
446 : /* fd_vinyl_data_free releases obj to the data cache. This cannot fail
447 : from the caller's perspective. Will FD_LOG_CRIT if anything wonky is
448 : detected (bad args, memory corruption, etc). */
449 :
450 : void
451 : fd_vinyl_data_free( fd_vinyl_data_t * data,
452 : fd_vinyl_data_obj_t * obj );
453 :
454 : /* fd_vinyl_data_reset uses the caller and tpool threads (t0,t1) to free
455 : all objects from the data cache. level zero/non-zero indicates to do
456 : soft/hard reset. In a hard reset, the shmem region is zero'd before
457 : formatting it into a set of free data volumes. This cannot fail from
458 : the caller's perspective. Assumes tpool threads (t0,t1) are
459 : available for dispatch. Retains no interest in tpool and tpool
460 : threads (t0,t1) will be available for dispatch on return. */
461 :
462 : void
463 : fd_vinyl_data_reset( fd_tpool_t * tpool, ulong t0, ulong t1, int level,
464 : fd_vinyl_data_t * data );
465 :
466 : /* fd_vinyl_data_verify returns FD_VINYL_SUCCESS (0) if the given data
467 : appears to be a valid vinyl data and FD_VINYL_ERR_CORRUPT (negative)
468 : otherwise (logs details). This only verifies the vinyl data's state
469 : and superblock heirarchy are intact. It does not test any of the
470 : allocations for correctness (but could given access to the bstream,
471 : line and/or meta). */
472 :
473 : int
474 : fd_vinyl_data_verify( fd_vinyl_data_t const * data );
475 :
476 : FD_PROTOTYPES_END
477 :
478 : #endif /* HEADER_fd_src_vinyl_data_fd_vinyl_data_h */
|