Line data Source code
1 : #ifndef HEADER_fd_src_groove_fd_groove_data_h
2 : #define HEADER_fd_src_groove_fd_groove_data_h
3 :
4 : //#include "fd_groove_base.h" /* includes ../util/fd_util.h */
5 : #include "fd_groove_meta.h" /* includes fd_groove_base.h */
6 : #include "fd_groove_volume.h" /* includes fd_groove_base.h */
7 :
8 : /* A groove data object has a worst case footprint (e.g. 10MiB). This
9 : footprint should be much larger than FD_GROOVE_BLOCK_FOOTPRINT and
10 : much smaller than FD_GROOVE_VOLUME_FOOTPRINT. A groove data object
11 : can have a zero footprint.
12 :
13 : A groove data object has a worst case alignment of at most
14 : FD_GROOVE_BLOCK_ALIGN.
15 :
16 : A groove data object is stored contiguously in a compact range of
17 : groove data blocks. Conversely, a groove data block can hold
18 : information about at most 1 groove data object.
19 :
20 : A groove data object is never split across multiple groove volumes.
21 :
22 : A groove data object has a header describing the object at the
23 : beginning of their first data block.
24 :
25 : Groove data objects of similar size (i.e. in the same "sizeclass")
26 : are grouped together into superblocks. Superblocks of a similar size
27 : are grouped together into larger superblocks. And so on until the
28 : superblock is the size of an entire groove volume.
29 :
30 : Volume sized superblocks are acquired from the lockfree volume pool.
31 :
32 : The lockfree algorithms are viritual identically to fd_alloc but the
33 : superblock nesting has been optimized for HPC memory mapped I/O,
34 : bounded size objects and using the (lockfree) volume pool instead of
35 : the (locking) wksp as the allocator of last resort. */
36 :
37 : /* fd_groove_data_szc_cfg[ szc ] specifies the configuration of
38 : sizeclass szc. */
39 :
40 : struct fd_groove_data_szc_cfg {
41 : uint obj_footprint; /* FD_GROOVE_BLOCK_FOOTPRINT multiple,
42 : superblock_footprint = FD_GROOVE_BLOCK_FOOTPRINT + obj_cnt*obj_footprint */
43 : uchar obj_cnt; /* ==number of objects in the superblock for this sizeclass, in [2,64] */
44 : uchar cgroup_mask; /* Number of concurrency groups to use for this sizeclass superblock (power-of-2) minus 1 */
45 : uchar parent_szc; /* Parent size class, SZC_CNT indicates to use an entire volume data region */
46 : };
47 :
48 : typedef struct fd_groove_data_szc_cfg fd_groove_data_szc_cfg_t;
49 :
50 4214625 : #define FD_GROOVE_DATA_ALLOC_ALIGN_DEFAULT FD_GROOVE_DATA_HDR_ALIGN
51 6 : #define FD_GROOVE_DATA_ALLOC_ALIGN_MAX FD_GROOVE_BLOCK_ALIGN
52 :
53 3 : #define FD_GROOVE_DATA_ALLOC_FOOTPRINT_MAX (10486272UL)
54 :
55 66173376 : #define FD_GROOVE_DATA_SZC_CNT (32UL)
56 : #define FD_GROOVE_DATA_SZC_CGROUP_MAX (64UL)
57 :
58 : extern fd_groove_data_szc_cfg_t const fd_groove_data_szc_cfg[32];
59 :
60 : /* A fd_groove_data_hdr encodes groove data object details:
61 :
62 : bits[ 0:15] 16 -> magic type
63 : bits[16:21] 6 -> object idx in parent (0 if parent is a volume)
64 : bits[22:28] 7 -> object sizeclass (type ALLOC), sizeclass of objects in superblock (type SUPERBLOCK)
65 : bits[29:38] 10 -> object align (type ALLOC), DATA_HDR_ALIGN (type SUPERBLOCK)
66 : bits[39:63] 25 -> object sz (type ALLOC), superblock sz (sat to 25-bits) (type SUPERBLOCK)
67 : info 64 -> object tag (type ALLOC), next superblock (type SUPERBLOCK)
68 :
69 : This layout assumes:
70 :
71 : - SZC_CNT <= 128 (such that a size class index fits in 7 bits)
72 : - superblocks have at most 64 objects (such that a object index fits
73 : in 6 bits)
74 : - groove data objects sizes are less than 32 MiB (such that sz fits
75 : in 25 bits)
76 : - groove data objects alignments are at most 512 (such that
77 : align fits in 10 bits)
78 :
79 : Note: The next superblock is given as an offset relative to volume0.
80 : This could be up to machine address width (64 bits). Since this
81 : offset is aligned 512, we could encode additional info there as the
82 : lower 9 bits are zero.
83 :
84 : Note: since alignments are powers of 2, we could use the log2 of the
85 : alignment to compact align further (it would be nice to store
86 : superblock offset in the header but this doesn't save enough space as
87 : the superblock offset needs ~30 bits ... would have to lose details
88 : like object sz and align or use a bigger header).
89 :
90 : Note: Consider an alternate design where these headers are seperated
91 : out (e.g. a mirror header for each data block at the start of the
92 : volume similar to wksp or a separate mirror header region entirely).
93 : Advantages would be better isolation / protection of headers, more
94 : advanced analytics / repair / etc. Disadvantages are ~5-6% storage
95 : overhead, more complexity for user to manage. Performance
96 : implications are mixed (less implicit prefetching and more hopping
97 : around but may be faster if header storage region runs on separate
98 : optimized media ... e.g. headers in fast NVMe while data in slow
99 : spinning rust). */
100 :
101 4228965 : #define FD_GROOVE_DATA_HDR_ALIGN (16UL)
102 189952827 : #define FD_GROOVE_DATA_HDR_FOOTPRINT (16UL)
103 :
104 6324438 : #define FD_GROOVE_DATA_HDR_TYPE_ALLOC (0xfd67UL)
105 61275 : #define FD_GROOVE_DATA_HDR_TYPE_SUPERBLOCK (0x0298UL)
106 :
107 : struct __attribute__((aligned(FD_GROOVE_DATA_HDR_ALIGN))) fd_groove_data_hdr {
108 :
109 : /* Top of a FD_GROOVE_BLOCK */
110 :
111 : ulong bits;
112 : ulong info;
113 :
114 : /* Lots of room for other hdr type dependent data here. E.g.
115 : FD_GROOVE_DATA_HDR_TYPE_SUPERBLOCK has a ulong free_objs bit field
116 : here (consider moving free_objs and next to different cache line?) */
117 :
118 : };
119 :
120 : typedef struct fd_groove_data_hdr fd_groove_data_hdr_t;
121 :
122 21 : #define FD_GROOVE_DATA_ALIGN (128UL)
123 : #define FD_GROOVE_DATA_FOOTPRINT() sizeof(fd_groove_data_shmem_t)
124 3 : #define FD_GROOVE_DATA_MAGIC (0xfd67007eda7a36c0UL) /* fd groove data mgc version 0 */
125 :
126 : struct __attribute__((aligned(FD_GROOVE_DATA_ALIGN))) fd_groove_data_shmem {
127 :
128 : /* This point is FD_GROOVE_DATA_ALIGN aligned */
129 :
130 : ulong magic; /* ==FD_GROOVE_DATA_MAGIC */
131 :
132 : /* Padding to FD_GROOVE_DATA_ALIGN alignment */
133 :
134 : /* active_slot indexed szc+SZC_CNT*cgroup */
135 :
136 : ulong active_slot[ FD_GROOVE_DATA_SZC_CNT*FD_GROOVE_DATA_SZC_CGROUP_MAX ] __attribute__((aligned(FD_GROOVE_DATA_ALIGN)));
137 :
138 : /* Padding to FD_GROOVE_DATA_ALIGN alignment */
139 :
140 : /* Since superblocks offsets are all aligned 512, we use the least
141 : significant 9 bits of inactive_stack as an ABA tag. We could also
142 : restrict the maximum size data to like 50B * 10MiB and move to most
143 : significant bits for a ~14 bit wide tag. We could use 128-bit wide
144 : inactive_stack, falling back on a weakly locking implementation if
145 : the target doesn't have FD_HAS_INT128). */
146 :
147 : ulong inactive_stack[ FD_GROOVE_DATA_SZC_CNT ] __attribute__((aligned(FD_GROOVE_DATA_ALIGN)));
148 :
149 : /* Padding to FD_GROOVE_DATA_ALIGN==FD_GROOVE_VOLUME_POOL_ALIGN alignment */
150 :
151 : fd_groove_volume_pool_shmem_t volume_pool[1];
152 :
153 : /* Padding to FD_GROOVE_DATA_ALIGN alignment */
154 :
155 : };
156 :
157 : typedef struct fd_groove_data_shmem fd_groove_data_shmem_t;
158 :
159 : struct fd_groove_data {
160 : fd_groove_volume_pool_t volume_pool[1]; /* volume_pool local join (shele is volume0) */
161 : ulong * active_slot; /* active slot for sizeclass szc and concurrency group cgroup at
162 : active_slot + szc + SZC_CNT*cgroup in the local address */
163 : ulong * inactive_stack; /* inactive stack for sizeclass szc at inactive_stack + szc in local address space */
164 : ulong cgroup_hint; /* cgroup_hint for this join */
165 : };
166 :
167 : typedef struct fd_groove_data fd_groove_data_t;
168 :
169 : FD_PROTOTYPES_BEGIN
170 :
171 : /* fd_groove_data_{align,footprint} returns the alignment and footprint
172 : needed for a memory region to hold a fd_groove_data's state. align
173 : will be an integer power-of-two and footprint will be a multiple of
174 : align.
175 :
176 : fd_groove_data_new formats a memory region with the appropriate
177 : alignment and footprint into a fd_groove_data. shmem points in the
178 : the caller's address space of the memory region to format. Returns
179 : shmem on success (fd_groove_data has ownership of the memory region)
180 : and NULL on failure (no changes, logs details). Caller is not joined
181 : on return. The fd_groove_data will contain no volumes and have no
182 : data allocations.
183 :
184 : fd_groove_data_join joins a fd_groove_data. ljoin points to a
185 : fd_groove_data_t compatible memory region in the caller's address
186 : space used to hold the local join's state, shdata points in the
187 : caller's address space to the memory region containing the
188 : fd_groove_data, volume0 points in the caller's address space reserved
189 : for mapping groove volumes, volume_max is the maximum number of
190 : volumes can be mapped in the caller's address space starting at
191 : volume0 (0 indicates to use as maximal default), and cgroup_hint is
192 : the concurrency group hint (see fd_alloc for details). Returns a
193 : handle to the caller's local join on success (join has ownership of
194 : the ljoin region) and NULL on failure (no changes, logs details).
195 :
196 : fd_groove_data_leave leaves a fd_groove_data. join points to a
197 : current local join. Returns the memory used for the local join
198 : (caller has ownership on return and caller is no longer joined) on
199 : success and NULL on failure (no changes, logs details). Use the join
200 : accessors before leaving to get shdata, volume0 and cgroup_hint used
201 : by the join if needed.
202 :
203 : fd_groove_data_delete unformats a memory region used as a
204 : fd_groove_data. Assumes shdata points in the caller's address space
205 : to the memory region containing the fd_groove_data and that there are
206 : no current joins globally. Returns shdata on success (caller has
207 : ownership of the memory region, any volumes in the groove and and any
208 : groove data objects in these volumes) and NULL on failure (no
209 : ownership changes, logs details). */
210 :
211 : /* FIXME: SHOULD HAVE A WAY FOR A JOIN TO TELL THE CALLER WHICH VOLUMES
212 : NEED TO BE MAPPED INTO THE CALLER'S ADDRESS SPACE (E.G. A VERSIONED
213 : PMAP AND HAVE CALLS INDICATE TO APPLICATION TO REMAP) */
214 :
215 0 : FD_FN_CONST static inline ulong fd_groove_data_align ( void ) { return alignof( fd_groove_data_shmem_t ); }
216 0 : FD_FN_CONST static inline ulong fd_groove_data_footprint( void ) { return sizeof ( fd_groove_data_shmem_t ); }
217 :
218 : void * fd_groove_data_new ( void * shmem );
219 : fd_groove_data_t * fd_groove_data_join ( void * ljoin, void * shdata, void * volume0, ulong volume_max, ulong cgroup_hint );
220 : void * fd_groove_data_leave ( fd_groove_data_t * join );
221 : void * fd_groove_data_delete( void * shdata );
222 :
223 : /* fd_groove_data_{shdata,volume0,volume_max,cgroup_hint} return
224 : {shdata,volume0,volume_max,cgroup_hint} used to join a
225 : fd_groove_data. fd_groove_data_volume1 returns the end of the groove
226 : region such that [volume0,volume1) is the groove data region.
227 : Assumes data is a current local join.
228 : fd_groove_data_{shdata,volume0,volume1}_const are const correct
229 : versions. shdata,volume0,volume1 are in the caller's address space. */
230 :
231 : FD_FN_PURE static inline void const *
232 18 : fd_groove_data_shdata_const( fd_groove_data_t const * data ) {
233 18 : return (void const *)((ulong)data->active_slot-FD_GROOVE_DATA_ALIGN);
234 18 : }
235 :
236 : FD_FN_PURE static inline void const *
237 9 : fd_groove_data_volume0_const( fd_groove_data_t const * data ) {
238 9 : return fd_groove_volume_pool_shele_const( data->volume_pool );
239 9 : }
240 :
241 : FD_FN_PURE static inline void const *
242 9 : fd_groove_data_volume1_const( fd_groove_data_t const * data ) {
243 9 : return (void const *)( (fd_groove_volume_t *)fd_groove_volume_pool_shele_const( data->volume_pool )
244 9 : + fd_groove_volume_pool_ele_max( data->volume_pool ) );
245 9 : }
246 :
247 : FD_FN_PURE static inline ulong
248 6 : fd_groove_data_volume_max( fd_groove_data_t const * data ) {
249 6 : return fd_groove_volume_pool_ele_max( data->volume_pool );
250 6 : }
251 :
252 : FD_FN_PURE static inline ulong
253 1898574 : fd_groove_data_cgroup_hint( fd_groove_data_t const * data ) {
254 1898574 : return data->cgroup_hint;
255 1898574 : }
256 :
257 : FD_FN_PURE static inline void *
258 3 : fd_groove_data_shdata( fd_groove_data_t * data ) {
259 3 : return (void *)((ulong)data->active_slot-FD_GROOVE_DATA_ALIGN);
260 3 : }
261 :
262 : FD_FN_PURE static inline void *
263 4231509 : fd_groove_data_volume0( fd_groove_data_t * data ) {
264 4231509 : return fd_groove_volume_pool_shele( data->volume_pool );
265 4231509 : }
266 :
267 : FD_FN_PURE static inline void *
268 4231506 : fd_groove_data_volume1( fd_groove_data_t * data ) {
269 4231506 : return (void *)( (fd_groove_volume_t *)fd_groove_volume_pool_shele( data->volume_pool ) +
270 4231506 : + fd_groove_volume_pool_ele_max( data->volume_pool ) );
271 4231506 : }
272 :
273 : /* fd_groove_data_hdr packs the given fields into a fd_groove_hdr_t. */
274 :
275 : FD_FN_CONST static inline fd_groove_data_hdr_t
276 : fd_groove_data_hdr( ulong type, /* assumed in [0,2^16) */
277 : ulong idx, /* assumed in [0,2^ 6) */
278 : ulong szc, /* assumed in [0,2^ 7) */
279 : ulong align, /* assumed in [0,2^10) */
280 : ulong sz, /* assumed in [0,2^25) */
281 32121642 : ulong info ) { /* arbitrary */
282 32121642 : fd_groove_data_hdr_t hdr;
283 32121642 : hdr.bits = type | (idx<<16) | (szc<<22) | (align<<29) | (sz<<39);
284 32121642 : hdr.info = info;
285 32121642 : return hdr;
286 32121642 : }
287 :
288 : /* fd_groove_data_hdr_* extract the given field from a fd_groove_hdr_t. */
289 :
290 66417873 : FD_FN_CONST static inline ulong /* <2^16 */ fd_groove_data_hdr_type ( fd_groove_data_hdr_t h ) { return h.bits & 65535UL; }
291 62186406 : FD_FN_CONST static inline ulong /* <2^ 6 */ fd_groove_data_hdr_idx ( fd_groove_data_hdr_t h ) { return (h.bits>>16) & 63UL; }
292 72717582 : FD_FN_CONST static inline ulong /* <2^ 7 */ fd_groove_data_hdr_szc ( fd_groove_data_hdr_t h ) { return (h.bits>>22) & 127UL; }
293 68477862 : FD_FN_CONST static inline ulong /* <2^10 */ fd_groove_data_hdr_align( fd_groove_data_hdr_t h ) { return (h.bits>>29) & 1023UL; }
294 68477862 : FD_FN_CONST static inline ulong /* <2^25 */ fd_groove_data_hdr_sz ( fd_groove_data_hdr_t h ) { return h.bits>>39 ; }
295 66299550 : FD_FN_CONST static inline ulong /* arb */ fd_groove_data_hdr_info ( fd_groove_data_hdr_t h ) { return h.info ; }
296 :
297 : /* fd_groove_data_{object,superblock}_hdr returns the header for a
298 : groove object / object superblock. Assumes obj points to the first
299 : object byte in the caller's address space. obj_szc is the object's
300 : sizeclass and parent_idx is the object's index in its parent
301 : superblock (and thus assumes the object is stored in a superblock).
302 : fd_groove_data_{alloc,superblock}_hdr_const are const correct
303 : versions. */
304 :
305 : FD_FN_CONST static inline fd_groove_data_hdr_t *
306 32109828 : fd_groove_data_object_hdr( void * obj ) {
307 32109828 : return (fd_groove_data_hdr_t *)fd_ulong_align_dn( (ulong)obj - FD_GROOVE_DATA_HDR_FOOTPRINT, FD_GROOVE_BLOCK_ALIGN );
308 32109828 : }
309 :
310 : FD_FN_PURE static inline fd_groove_data_hdr_t *
311 : fd_groove_data_superblock_hdr( void * obj,
312 : ulong obj_szc,
313 32109828 : ulong parent_idx ) {
314 32109828 : return (fd_groove_data_hdr_t *)
315 32109828 : ( fd_ulong_align_dn( (ulong)obj - FD_GROOVE_DATA_HDR_FOOTPRINT, FD_GROOVE_BLOCK_ALIGN )
316 32109828 : - parent_idx*(ulong)fd_groove_data_szc_cfg[ obj_szc ].obj_footprint - FD_GROOVE_BLOCK_FOOTPRINT );
317 32109828 : }
318 :
319 : FD_FN_CONST static inline fd_groove_data_hdr_t const *
320 61457280 : fd_groove_data_object_hdr_const( void const * obj ) {
321 61457280 : return (fd_groove_data_hdr_t const *)fd_ulong_align_dn( (ulong)obj - FD_GROOVE_DATA_HDR_FOOTPRINT, FD_GROOVE_BLOCK_ALIGN );
322 61457280 : }
323 :
324 : FD_FN_PURE static inline fd_groove_data_hdr_t const *
325 : fd_groove_data_superblock_hdr_const( void const * obj,
326 : ulong obj_szc,
327 30000000 : ulong parent_idx ) {
328 30000000 : return (fd_groove_data_hdr_t const *)
329 30000000 : ( fd_ulong_align_dn( (ulong)obj - FD_GROOVE_DATA_HDR_FOOTPRINT, FD_GROOVE_BLOCK_ALIGN )
330 30000000 : - parent_idx*(ulong)fd_groove_data_szc_cfg[ obj_szc ].obj_footprint - FD_GROOVE_BLOCK_FOOTPRINT );
331 30000000 : }
332 :
333 : /* fd_groove_data_szc returns the index of the tightest fitting
334 : sizeclass for footprint. The caller promises there is at least one
335 : suitable sizeclass (i.e. footprint<=cfg[SZC_CNT-1].obj_footprint).
336 : The return will be in [0,FD_GROOVE_DATA_SZC_CNT). */
337 :
338 : static inline ulong
339 32107305 : fd_groove_data_szc( ulong footprint ) {
340 32107305 : ulong l = 0UL;
341 32107305 : ulong h = FD_GROOVE_DATA_SZC_CNT - 1UL;
342 :
343 : /* Fixed count loop without early exit to make it easy for compiler to
344 : unroll and nominally eliminate all branches for fast, highly
345 : deterministic performance with no consumption of BTB resources.
346 : FIXME: check the compiler is doing the right thing here. */
347 :
348 192643830 : for( ulong r=0UL; r<5UL; r++ ) { /* Assumes SZC_CNT<=32 */
349 :
350 : /* At this point sizeclasses in [0,l) are known too small and
351 : sizeclasses [h,SZC_CNT) are known large enough. Sizeclasses in
352 : [l,h) have not been tested. The size of the range will be
353 : decreased to at least floor((h-l)/2) every iteration. If this
354 : range is empty, m==l==h and c==1 as there m must be the tightest
355 : size class such that the l/h updates are no-ops. */
356 :
357 160536525 : ulong m = (l+h)>>1; /* No overflow for reasonable SZC_CNT */
358 160536525 : int c = (((ulong)fd_groove_data_szc_cfg[ m ].obj_footprint)>=footprint);
359 160536525 : l = fd_ulong_if( c, l, m+1UL ); /* cmov */
360 160536525 : h = fd_ulong_if( c, m, h ); /* cmov */
361 160536525 : }
362 :
363 32107305 : return h;
364 32107305 : }
365 :
366 : /* fd_groove_data_volume_{add,remove} are just thin wrappers around the
367 : volume pool APIs for data's volume_pool. See the volume_pool API for
368 : details. */
369 :
370 : static inline int
371 : fd_groove_data_volume_add( fd_groove_data_t * data,
372 : void * volume,
373 : ulong footprint,
374 : void const * info,
375 9 : ulong info_sz ) {
376 9 : return fd_groove_volume_pool_add( data ? data->volume_pool : NULL, volume, footprint, info, info_sz );
377 9 : }
378 :
379 : static inline void *
380 9 : fd_groove_data_volume_remove( fd_groove_data_t * data ) {
381 9 : return fd_groove_volume_pool_remove( data ? data->volume_pool : NULL );
382 9 : }
383 :
384 : /* fd_groove_data_alloc creates a groove data object in the groove data
385 : store with the given alignment, size and arbitrary user tag. Align
386 : should be an integer power of 2 of at most
387 : FD_GROOVE_DATA_ALLOC_ALIGN_MAX or 0 (0 indicates to use
388 : FD_GROOVE_DATA_ALLOC_ALIGN_DEFAULT). Assumes data is current local
389 : join. Because every allocation is independently tagged, a zero size
390 : allocation will produce a unique non-NULL return.
391 :
392 : On success, returns a pointer in the caller's address to the created
393 : object (will be aligned align with room for sz bytes). The lifetime
394 : of the _object_ is until it is freed or the data store is destroyed.
395 : The lifetime of the local _pointer_ is until the object is freed or
396 : the join is left. If _opt_err is non-NULL, *_opt_err will be
397 : FD_GROOVE_SUCCESS (zero).
398 :
399 : On failure, returns NULL. If _opt_err is non-NULL, *_opt_err will be
400 : an FD_GROOVE_ERR code (negative). Reasons for failure include:
401 : INVAL (logged) - bad input args (NULL data, align not power of 2, align too large, sz too large)
402 : FULL (silent) - groove too full for allocation right now */
403 :
404 : void *
405 : fd_groove_data_alloc( fd_groove_data_t * data,
406 : ulong align,
407 : ulong sz,
408 : ulong tag,
409 : int * _opt_err );
410 :
411 : /* fd_groove_data_free frees a groove data object in the groove data
412 : store. Assumes obj points to the first byte in the object in the
413 : caller's address space. On return, obj is no longer a groove data
414 : obj. On success, returns FD_GROOVE_SUCCESS (0) and a FD_GROOVE_ERR
415 : code (negative) on failure. Reasons for failure include:
416 :
417 : INVAL - NULL data (logged), NULL obj (silent), all sorts of
418 : unexpected conditions that suggest buggy usage and/or data
419 : corruption (logged), groove data state was not changed.
420 :
421 : CORRUPT - all sorts of unexpected conditions that suggest buggy
422 : usage and/or data corruption (logged), groove data state might
423 : have been changed before the unexpected condition was detected. */
424 :
425 : int
426 : fd_groove_data_private_free( fd_groove_data_t * data,
427 : void * obj,
428 : ulong exp_type );
429 :
430 : static inline int
431 : fd_groove_data_free( fd_groove_data_t * data,
432 2107308 : void * obj ) {
433 2107308 : return fd_groove_data_private_free( data, obj, FD_GROOVE_DATA_HDR_TYPE_ALLOC );
434 2107308 : }
435 :
436 : /* fd_groove_data_{align,sz,tag} return the values used when obj was
437 : allocated. Assumes obj points in the caller's address space to a
438 : current allocation in the groove data. */
439 :
440 : FD_FN_PURE static inline ulong
441 6291456 : fd_groove_data_alloc_align( void const * obj ) {
442 6291456 : return fd_groove_data_hdr_align( *fd_groove_data_object_hdr_const( obj ) );
443 6291456 : }
444 :
445 : FD_FN_PURE static inline ulong
446 6291456 : fd_groove_data_alloc_sz( void const * obj ) {
447 6291456 : return fd_groove_data_hdr_sz( *fd_groove_data_object_hdr_const( obj ) );
448 6291456 : }
449 :
450 : FD_FN_PURE static inline ulong
451 6291456 : fd_groove_data_alloc_tag( void const * obj ) {
452 6291456 : return fd_groove_data_hdr_info( *fd_groove_data_object_hdr_const( obj ) );
453 6291456 : }
454 :
455 : /* fd_groove_data_{start,stop} return the actual range of addresses
456 : [start,stop) in the caller's address space actually reserved for the
457 : allocation obj. [obj,obj+sz) is completely covered by this region
458 : (and obj will be aligned appropriately).
459 :
460 : fd_groove_data_{start,stop}_const are const correct versions. */
461 :
462 : FD_FN_CONST static inline void *
463 2107302 : fd_groove_data_alloc_start( void * obj ) {
464 2107302 : return (void *)((ulong)fd_groove_data_object_hdr_const( obj ) + 16UL);
465 2107302 : }
466 :
467 : FD_FN_PURE static inline void *
468 2107302 : fd_groove_data_alloc_stop( void * obj ) {
469 2107302 : fd_groove_data_hdr_t const * hdr = fd_groove_data_object_hdr_const( obj );
470 2107302 : return (void *)((ulong)hdr + (ulong)fd_groove_data_szc_cfg[ fd_groove_data_hdr_szc( *hdr ) ].obj_footprint);
471 2107302 : }
472 :
473 : FD_FN_CONST static inline void const *
474 4184154 : fd_groove_data_alloc_start_const( void const * obj ) {
475 4184154 : return (void const *)((ulong)fd_groove_data_object_hdr_const( obj ) + 16UL);
476 4184154 : }
477 :
478 : FD_FN_PURE static inline void const *
479 4184154 : fd_groove_data_alloc_stop_const( void const * obj ) {
480 4184154 : fd_groove_data_hdr_t const * hdr = fd_groove_data_object_hdr_const( obj );
481 4184154 : return (void const *)((ulong)hdr + (ulong)fd_groove_data_szc_cfg[ fd_groove_data_hdr_szc( *hdr ) ].obj_footprint);
482 4184154 : }
483 :
484 : /* fd_groove_data_verify returns FD_GROOVE_SUCCESS if join appears to be
485 : current local join to a valid groove data instance and
486 : FD_GROOVE_ERR_CORRUPT otherwise (logs details). Assumes join is a
487 : current local join and the groove data is idle. This only verifies
488 : the groove data's state. Specifically, it verifies the join, the
489 : data volume pool, the active superblocks and the inactive superblocks
490 : look correct. It is does verify the entire containts of all volumes.
491 : Use fd_groove_data_verify for that. */
492 :
493 : int
494 : fd_groove_data_verify( fd_groove_data_t const * data );
495 :
496 : /* fd_groove_data_volume_verify returns FD_GROOVE_SUCCESS if the
497 : groove volume mapped into the caller's address at _volume is appears
498 : to be a valid groove volume and and FD_GROOVE_ERR_CORRUPT
499 : otherwise (logs details). Assumes join is a current local join and
500 : the groove data is idle. It is fine to verify volumes in parallel
501 : (e.g. use hundreds of cores to verify petabytes of groove data). */
502 :
503 : int
504 : fd_groove_data_volume_verify( fd_groove_data_t const * data,
505 : fd_groove_volume_t const * _volume );
506 :
507 : FD_PROTOTYPES_END
508 :
509 : #endif /* HEADER_fd_src_groove_fd_groove_data_h */
|