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 : #include "../../util/tpool/fd_tpool.h"
79 :
80 4417008 : #define FD_VINYL_DATA_VOL_FOOTPRINT (41944192UL) /* autogenerated */
81 39142140 : #define FD_VINYL_DATA_SZC_CNT (83UL) /* autogenerated */
82 31457454 : #define FD_VINYL_DATA_SZC_ITER_MAX (7UL) /* autogenerated */
83 :
84 : /* fd_vinyl_data_szc **************************************************/
85 :
86 : struct __attribute__((aligned(8))) fd_vinyl_data_szc_cfg {
87 : uint val_max; /* max pair val byte size that can be stored in an object in this size class.
88 : The object is aligned in memory with FD_VINYL_BSTREAM_BLOCK_SZ alignment and with a footprint of:
89 : FD_VINYL_BSTREAM_BLOCK_SZ + sizeof(fd_vinyl_bstream_phdr_t) + val_max + FD_VINYL_BSTREAM_FTR_SZ
90 : The footprint is a FD_VINYL_BSTREAM_BLOCK_SZ multiple. */
91 : ushort obj_cnt; /* ==num objects in the containing superblock, in [2,64] */
92 : ushort parent_szc; /* size class of the superblock that contains objects of this size class,
93 : FD_VINYL_DATA_SZC_CNT indicates superblocks for objects of this size class fill an entire volume,
94 : (the superblock footprint is FD_VINYL_BSTREAM_BLOCK_SZ + obj_cnt*obj_footprint) */
95 : };
96 :
97 : typedef struct fd_vinyl_data_szc_cfg fd_vinyl_data_szc_cfg_t;
98 :
99 : FD_PROTOTYPES_BEGIN
100 :
101 : /* fd_vinyl_data_szc_cfg describes the sizeclasses used by the data
102 : cache. Indexed [0,FD_VINYL_DATA_SZC_CNT). */
103 :
104 : extern fd_vinyl_data_szc_cfg_t const fd_vinyl_data_szc_cfg[ FD_VINYL_DATA_SZC_CNT ];
105 :
106 : /* fd_vinyl_data_szc_obj_footprint returns the in-memory footprint for
107 : an object with the given size class.
108 :
109 : fd_vinyl_data_szc_val_max returns the largest pair val that can be
110 : cached in an object with the given size class. Assumes szc is in
111 : [O,FD_VINYL_DATA_SZC_CNT). Return will be in
112 : [0,cfg(SZC_CNT-1).val_max].
113 :
114 : fd_vinyl_data_szc returns the tightest fitting size class that can
115 : cache a pair val with a maximum size of val_max. Assumes val_max is
116 : in [0,szc.cfg(SZC_CNT-1.val_max]. Return will be in
117 : [0,FD_VINYL_DATA_SZC_CNT). The returned size class is typically able
118 : to hold a val_max ~1-2% larger than the given val_max.
119 :
120 : Note that the size classes are configured such that, given val_sz in
121 : [0,FD_VINYL_VAL_MAX]:
122 :
123 : fd_vinyl_data_szc_val_max( fd_vinyl_data_szc( val_sz ) ) <= FD_VINYL_VAL_MAX.
124 :
125 : where equality is achieved when val_sz==FD_VINYL_VAL_MAX.
126 :
127 : FIXME: should these be FD_FN_CONST (szc_cfg is const)? */
128 :
129 : FD_FN_PURE static inline ulong
130 5914674 : fd_vinyl_data_szc_obj_footprint( ulong szc ) {
131 5914674 : return FD_VINYL_BSTREAM_BLOCK_SZ +
132 5914674 : sizeof(fd_vinyl_bstream_phdr_t) + (ulong)fd_vinyl_data_szc_cfg[ szc ].val_max + FD_VINYL_BSTREAM_FTR_SZ;
133 5914674 : }
134 :
135 : FD_FN_PURE static inline ulong
136 14899077 : fd_vinyl_data_szc_val_max( ulong szc ) {
137 14899077 : return (ulong)fd_vinyl_data_szc_cfg[ szc ].val_max;
138 14899077 : }
139 :
140 : FD_FN_PURE static inline ulong
141 31457454 : fd_vinyl_data_szc( ulong val_max ) {
142 :
143 31457454 : ulong l = 0UL;
144 31457454 : ulong h = FD_VINYL_DATA_SZC_CNT-1UL;
145 :
146 251659632 : for( ulong rem=FD_VINYL_DATA_SZC_ITER_MAX; rem; rem-- ) {
147 :
148 : /* At this point, szc in [0,l) aren't suitable, szc in [h,CNT) are
149 : suitable and szc in [l,h) are untested. See fd_alloc for more
150 : detail on using fixed count loop. */
151 :
152 220202178 : ulong m = (l+h) >> 1;
153 220202178 : int c = (((ulong)fd_vinyl_data_szc_cfg[ m ].val_max) >= val_max);
154 220202178 : l = fd_ulong_if( c, l, m+1UL );
155 220202178 : h = fd_ulong_if( c, m, h );
156 :
157 220202178 : }
158 :
159 31457454 : return l;
160 31457454 : }
161 :
162 : FD_PROTOTYPES_END
163 :
164 : /* fd_vinyl_data_obj **************************************************/
165 :
166 1050 : #define FD_VINYL_DATA_OBJ_TYPE_FREEVOL (0xf7eef7eef7eef7eeUL) /* free, object is a free volume */
167 1456068 : #define FD_VINYL_DATA_OBJ_TYPE_ALLOC (0xa11ca11ca11ca11cUL) /* allc, object is an allocation */
168 552570 : #define FD_VINYL_DATA_OBJ_TYPE_SUPERBLOCK (0x59e759e759e759e7UL) /* sper, object is a superblock */
169 :
170 : #define FD_VINYL_DATA_OBJ_GUARD_SZ (FD_VINYL_BSTREAM_BLOCK_SZ - sizeof(fd_vinyl_io_rd_t) - 8UL*sizeof(ulong))
171 :
172 : struct fd_vinyl_data_obj;
173 : typedef struct fd_vinyl_data_obj fd_vinyl_data_obj_t;
174 :
175 : struct __attribute__((aligned(FD_VINYL_BSTREAM_BLOCK_SZ))) fd_vinyl_data_obj {
176 :
177 : /* type gives the object type. A FD_VINYL_DATA_OBJ_TYPE_*.
178 :
179 : For type SUPERBLOCK objects, child_szc gives the size class of the
180 : objects contained in this superblock. In
181 : [0,FD_VINYL_DATA_SZC_CNT). Ignored for other types of objects.
182 :
183 : For type SUPERBLOCK and type ALLOC objects, szc gives the size
184 : class of the object. In [0,FD_VINYL_DATA_SZC_CNT]. Values less
185 : then SZC_CNT indicate an object contained in a superblock. Equal
186 : to SZC_CNT indicates an object that fills an entire volume. For
187 : other types of objects, ignored.
188 :
189 : For objects contained in a parent superblock, idx gives the index
190 : of the object in its parent, in [0,szc.obj_cnt). For objects that
191 : fill an entire volume, idx gives the data volume index, in
192 : [0,vol_cnt).
193 :
194 : For type SUPERBLOCK objects, free_blocks gives a bit field
195 : identifying which blocks are free. Ignored for other types of
196 : objects.
197 :
198 : For inactive type SUPERBLOCK objects, next_off gives the byte
199 : offset from laddr0 of the next inactive superblock and 0UL if no
200 : more inactive superblocks. next_off is ignored in other
201 : circumstances (but see note about pending I/O ops). Note that this
202 : implies laddr0 must less than the local address of vol (such that
203 : data gaddr==0 never points to an object). Note also that, if
204 : laddr0 is 0, next_off will be just a pointer in the local address
205 : space.
206 :
207 : Note that I/O acceleration may require memory alignment and I/O
208 : device alignment to match. So we need to put all the object
209 : allocator data its own block. This can leave a lot of extra space.
210 : We put this space up front in the block to that it can act as a
211 : guard region for whatever precedes it (applications could even use
212 : this guard region to stash extra info but this is not recommended
213 : because of false sharing conflicts in might induce between
214 : different threads using adjacent in memory objects). Likewise,
215 : because we have all this space from block quantization, we don't
216 : try to be hyperefficient with the packing (like we do for, say,
217 : fd_alloc). */
218 :
219 : # if 0 /* Note: with BLOCK_SZ==128, GUARD_SZ=0 so there's no guard field due to language limitations */
220 : uchar guard[ FD_VINYL_DATA_OBJ_GUARD_SZ ];
221 : # endif
222 :
223 : /* rd on its own cache line */
224 :
225 : fd_vinyl_io_rd_t rd[1]; /* rd: ctx is element idx */
226 :
227 : /* allocator metadata on its own cache line */
228 :
229 : ulong unused[1]; /* unused space */
230 : schar * rd_err; /* rd: client req_err (or dummy location if no client req_err) */
231 : short rd_active; /* rd: is a read in progress on this obj */
232 : ushort _unused; /* unused space */
233 : ushort szc; /* data: allocation size class */
234 : ushort child_szc; /* data: (superblock) contains allocations of this sizeclass */
235 : ulong line_idx; /* vinyl line_idx that is responsible for this object, in [0,line_cnt), ignored if not type alloc */
236 : ulong type; /* data: allocation type (alloc or superblock) */
237 : ulong idx; /* data: (alloc or superblock) index of this allocation in its parent superblock, (vol) vol idx */
238 : ulong free_blocks; /* data: (superblock) bit field free allocations */
239 : ulong next_off; /* data: (inactive superblock) pointer to next inactive superblock or 0 last */
240 :
241 : /* This point is FD_VINYL_BSTREAM_BLOCK_SZ aligned */
242 :
243 : /* Space for sizeof(fd_vinyl_bstream_phdr_t) + fd_vinyl_data_szc_cfg[szc].val_max + FD_VINYL_BSTREAM_FTR_SZ
244 :
245 : Note that is is a FD_VINYL_BSTREAM_BLOCK_SZ multiple so that the
246 : entire region starting from phdr can submitted zero copy for
247 : streaming to hardware async direct I/O friendly. */
248 :
249 : /* This point is FD_VINYL_BSTREAM_BLOCK_SZ aligned */
250 :
251 : /* There is an implied FD_VINYL_DATA_OBJ_GUARD_SZ region here as per
252 : note above. It is not considered part of _this_ data_obj_t though. */
253 :
254 : };
255 :
256 : FD_PROTOTYPES_BEGIN
257 :
258 : /* fd_vinyl_data_obj_* returns a pointer to the eponymous field in
259 : the given data object. Assumes obj is valid. Returns value for
260 : fd_vinyl_data_obj_phdr will be FD_VINYL_BSTREAM_BLOCK_SZ aligned.
261 : fd_vinyl_data_* mirror the above but they take the value region as
262 : input. */
263 :
264 : FD_FN_CONST static inline fd_vinyl_bstream_phdr_t *
265 3000000 : fd_vinyl_data_obj_phdr( fd_vinyl_data_obj_t const * obj ) {
266 3000000 : return (fd_vinyl_bstream_phdr_t *)((ulong)obj + sizeof(fd_vinyl_data_obj_t));
267 3000000 : }
268 :
269 : FD_FN_CONST static inline fd_vinyl_key_t *
270 3000000 : fd_vinyl_data_obj_key( fd_vinyl_data_obj_t const * obj ) {
271 3000000 : return (fd_vinyl_key_t *)((ulong)obj + sizeof(fd_vinyl_data_obj_t) + sizeof(ulong));
272 3000000 : }
273 :
274 : FD_FN_CONST static inline fd_vinyl_info_t *
275 6000000 : fd_vinyl_data_obj_info( fd_vinyl_data_obj_t const * obj ) {
276 6000000 : return (fd_vinyl_info_t *)((ulong)obj + sizeof(fd_vinyl_data_obj_t) + sizeof(ulong) + sizeof(fd_vinyl_key_t));
277 6000000 : }
278 :
279 : FD_FN_CONST static inline void *
280 3000000 : fd_vinyl_data_obj_val( fd_vinyl_data_obj_t const * obj ) {
281 3000000 : return (void *)((ulong)obj + sizeof(fd_vinyl_data_obj_t) + sizeof(fd_vinyl_bstream_phdr_t));
282 3000000 : }
283 :
284 : FD_FN_PURE static inline ulong
285 3000000 : fd_vinyl_data_obj_val_sz( fd_vinyl_data_obj_t const * obj ) {
286 3000000 : return (ulong)fd_vinyl_data_obj_info( obj )->val_sz;
287 3000000 : }
288 :
289 : FD_FN_PURE static inline ulong
290 3000000 : fd_vinyl_data_obj_val_max( fd_vinyl_data_obj_t const * obj ) {
291 3000000 : return fd_vinyl_data_szc_val_max( (ulong)obj->szc );
292 3000000 : }
293 :
294 : FD_FN_CONST static inline fd_vinyl_data_obj_t *
295 6000000 : fd_vinyl_data_obj( void const * val ) {
296 6000000 : return (fd_vinyl_data_obj_t *)((ulong)val - sizeof(fd_vinyl_bstream_phdr_t) - sizeof(fd_vinyl_data_obj_t));
297 6000000 : }
298 :
299 : FD_FN_CONST static inline fd_vinyl_bstream_phdr_t *
300 3000000 : fd_vinyl_data_phdr( void const * val ) {
301 3000000 : return (fd_vinyl_bstream_phdr_t *)((ulong)val - sizeof(fd_vinyl_bstream_phdr_t));
302 3000000 : }
303 :
304 : FD_FN_CONST static inline fd_vinyl_key_t *
305 3000000 : fd_vinyl_data_key( void const * val ) {
306 3000000 : return (fd_vinyl_key_t *)((ulong)val - sizeof(fd_vinyl_info_t) - sizeof(fd_vinyl_key_t));
307 3000000 : }
308 :
309 : FD_FN_CONST static inline fd_vinyl_info_t *
310 6000000 : fd_vinyl_data_info( void const * val ) {
311 6000000 : return (fd_vinyl_info_t *)((ulong)val - sizeof(fd_vinyl_info_t));
312 6000000 : }
313 :
314 : FD_FN_PURE static inline ulong
315 3000000 : fd_vinyl_data_val_sz( void const * val ) {
316 3000000 : return (ulong)fd_vinyl_data_info( val )->val_sz;
317 3000000 : }
318 :
319 : FD_FN_PURE static inline ulong
320 3000000 : fd_vinyl_data_val_max( void const * val ) {
321 3000000 : return fd_vinyl_data_szc_val_max( (ulong)fd_vinyl_data_obj( val )->szc );
322 3000000 : }
323 :
324 : FD_PROTOTYPES_END
325 :
326 : /* fd_vinyl_data_vol **************************************************/
327 :
328 : struct fd_vinyl_data_vol {
329 : fd_vinyl_data_obj_t obj[1];
330 : uchar data[ FD_VINYL_DATA_VOL_FOOTPRINT - sizeof(fd_vinyl_data_obj_t) ];
331 : };
332 :
333 : typedef struct fd_vinyl_data_vol fd_vinyl_data_vol_t;
334 :
335 : /* fd_vinyl_data ******************************************************/
336 :
337 : #define FD_VINYL_DATA_ALIGN (128UL)
338 : #define FD_VINYL_DATA_FOOTPRINT sizeof(fd_vinyl_data_t)
339 :
340 : struct __attribute((aligned(FD_VINYL_DATA_ALIGN))) fd_vinyl_data {
341 : void * shmem; /* Raw shared memory region */
342 : ulong shmem_sz; /* Raw shared memory region size */
343 : void * laddr0; /* Location where gaddr 0 points in the local address space
344 : (FD_VINYL_BSTREAM_BLOCK_SZ aligned) */
345 : fd_vinyl_data_vol_t * vol; /* Vols, indexed [0,vol_cnt), in raw shared memory region */
346 : ulong vol_cnt; /* Num vols, in [0,FD_VINYL_DATA_VOL_MAX) */
347 : ulong vol_idx_free; /* Idx of first free volume if in [0,vol_cnt), no free volumes o.w. */
348 : struct {
349 : fd_vinyl_data_obj_t * active; /* active superblock for this size class */
350 : fd_vinyl_data_obj_t * inactive_top; /* top of the inactive superblock stack for this size class */
351 : } superblock[ FD_VINYL_DATA_SZC_CNT ];
352 : };
353 :
354 : typedef struct fd_vinyl_data fd_vinyl_data_t;
355 :
356 : FD_PROTOTYPES_BEGIN
357 :
358 : /* fd_vinyl_data_{align,footprint} return the alignment and footprint
359 : needed for a local memory region to hold the state of a data cache.
360 : align will be a power of 2 and footprint will be a multiple of align.
361 : Matches FD_VINYL_DATA_{ALIGN,FOOTPRINT}. */
362 :
363 : FD_FN_CONST ulong fd_vinyl_data_align ( void );
364 : FD_FN_CONST ulong fd_vinyl_data_footprint( void );
365 :
366 : /* fd_vinyl_data_init formats a suitable local memory region lmem and an
367 : arbitrary shared memory region shmem with byte size shmem_sz as a
368 : vinyl data cache. laddr0 gives the location in the caller's local
369 : address space that corresponds to data object global address 0. It
370 : should be FD_VINYL_BSTREAM_BLOCK_SZ aligned and before shmem. E.g.
371 : laddr0==NULL could be used when the data objects aren't shared with
372 : threads in different processes while laddr0==wksp could be used for
373 : data objects that are shared and backed by a wksp.
374 :
375 : IMPORTANT SAFETY TIP! This does _not_ do the initial formatting of
376 : the shmem region into free data volumes (e.g. the caller can use the
377 : data shmem region as a scratch during thread parallel resume and then
378 : format it appropriately). The caller is responsible for calling
379 : fd_vinyl_data_reset before using data as an object store.
380 :
381 : Returns a handle to the data cache on success (data cache owns the
382 : memory regions) and NULL on failure (bad lmem, bad shmem, too small
383 : size ... logs details, no ownership changes). */
384 :
385 : fd_vinyl_data_t *
386 : fd_vinyl_data_init( void * lmem,
387 : void * shmem,
388 : ulong shmem_sz,
389 : void * laddr0 );
390 :
391 : /* fd_vinyl_data_fini stops using lmem and shmem as a data cache.
392 : Returns lmem on success and NULL on failure (logs details). */
393 :
394 : void *
395 : fd_vinyl_data_fini( fd_vinyl_data_t * data );
396 :
397 : /* fd_vinyl_data_{laddr0,shmem,shmem_sz} return the address translation
398 : and shared memory region used by the data cache. */
399 :
400 3 : FD_FN_PURE static inline void * fd_vinyl_data_laddr0 ( fd_vinyl_data_t const * data ) { return (void *)data->laddr0; }
401 3 : FD_FN_PURE static inline void * fd_vinyl_data_shmem ( fd_vinyl_data_t const * data ) { return (void *)data->shmem; }
402 3 : FD_FN_PURE static inline ulong fd_vinyl_data_shmem_sz( fd_vinyl_data_t const * data ) { return data->shmem_sz; }
403 :
404 : /* fd_vinyl_data_is_valid_obj returns 1 if laddr appears to point to
405 : a valid data object and 0 if not. vol points to data volume 0 in the
406 : local address space and vol_cnt is the number of data volumes. */
407 :
408 : FD_FN_PURE static inline int
409 : fd_vinyl_data_is_valid_obj( void const * laddr,
410 : fd_vinyl_data_vol_t const * vol,
411 4252611 : ulong vol_cnt ) {
412 :
413 4252611 : ulong vol_idx = ((ulong)laddr - (ulong)vol) / FD_VINYL_DATA_VOL_FOOTPRINT;
414 :
415 4252611 : if( FD_UNLIKELY( !( ((ulong)vol<=(ulong)laddr) &
416 4252611 : (vol_idx<vol_cnt) &
417 4252611 : fd_ulong_is_aligned( (ulong)laddr, FD_VINYL_BSTREAM_BLOCK_SZ ) ) ) ) return 0;
418 :
419 : /* At this point, laddr seems to be properly aligned and in volume
420 : vol_idx. We are safe to read the type and sizeclass. */
421 :
422 4252611 : fd_vinyl_data_obj_t const * obj = (fd_vinyl_data_obj_t const *)laddr;
423 4252611 : ulong szc = (ulong)obj->szc;
424 :
425 4252611 : if( FD_UNLIKELY( !((obj->type==FD_VINYL_DATA_OBJ_TYPE_ALLOC) & (szc<FD_VINYL_DATA_SZC_CNT)) ) ) return 0;
426 :
427 : /* At this point, laddr seems to contain an allocation of sizeclass
428 : szc. Make sure the object idx seems to be valid and the object is
429 : contained entirely within volume vol_idx. */
430 :
431 2851011 : ulong end = (ulong)laddr + fd_vinyl_data_szc_obj_footprint( szc );
432 :
433 2851011 : if( FD_UNLIKELY( !((obj->idx<(ulong)fd_vinyl_data_szc_cfg[ szc ].obj_cnt) & (end<=(ulong)&vol[vol_idx+1UL])) ) ) return 0;
434 :
435 2851011 : return 1;
436 2851011 : }
437 :
438 : /* fd_vinyl_data_alloc acquires an object of sizeclass szc from the data
439 : cache. Returns a pointer to the object on success and NULL if there
440 : is no space available in the data. Will FD_LOG_CRIT if anything
441 : wonky is detected (bad, memory corruption, etc). */
442 :
443 : fd_vinyl_data_obj_t *
444 : fd_vinyl_data_alloc( fd_vinyl_data_t * data,
445 : ulong szc );
446 :
447 : /* fd_vinyl_data_free releases obj to the data cache. This cannot fail
448 : from the caller's perspective. Will FD_LOG_CRIT if anything wonky is
449 : detected (bad args, memory corruption, etc). */
450 :
451 : void
452 : fd_vinyl_data_free( fd_vinyl_data_t * data,
453 : fd_vinyl_data_obj_t * obj );
454 :
455 : /* fd_vinyl_data_reset uses the caller and tpool threads (t0,t1) to free
456 : all objects from the data cache. level zero/non-zero indicates to do
457 : soft/hard reset. In a hard reset, the shmem region is zero'd before
458 : formatting it into a set of free data volumes. This cannot fail from
459 : the caller's perspective. Assumes tpool threads (t0,t1) are
460 : available for dispatch. Retains no interest in tpool and tpool
461 : threads (t0,t1) will be available for dispatch on return. */
462 :
463 : void
464 : fd_vinyl_data_reset( fd_tpool_t * tpool, ulong t0, ulong t1, int level,
465 : fd_vinyl_data_t * data );
466 :
467 : /* fd_vinyl_data_verify returns FD_VINYL_SUCCESS (0) if the given data
468 : appears to be a valid vinyl data and FD_VINYL_ERR_CORRUPT (negative)
469 : otherwise (logs details). This only verifies the vinyl data's state
470 : and superblock hierarchy are intact. It does not test any of the
471 : allocations for correctness (but could given access to the bstream,
472 : line and/or meta). */
473 :
474 : int
475 : fd_vinyl_data_verify( fd_vinyl_data_t const * data );
476 :
477 : FD_PROTOTYPES_END
478 :
479 : #endif /* HEADER_fd_src_vinyl_data_fd_vinyl_data_h */
|