LCOV - code coverage report
Current view: top level - groove - fd_groove_data.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 107 109 98.2 %
Date: 2025-03-20 12:08:36 Functions: 46 192 24.0 %

          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 */

Generated by: LCOV version 1.14