LCOV - code coverage report
Current view: top level - vinyl/data - fd_vinyl_data.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 74 74 100.0 %
Date: 2026-02-13 06:06:24 Functions: 20 494 4.0 %

          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             : /* fd_vinyl_data_szc **************************************************/
      80             : 
      81             : struct __attribute__((aligned(8))) fd_vinyl_data_szc_cfg {
      82             :   uint   val_max;    /* max pair val byte size that can be stored in an object in this size class.
      83             :                         The object is aligned in memory with FD_VINYL_BSTREAM_BLOCK_SZ alignment and with a footprint of:
      84             :                           FD_VINYL_BSTREAM_BLOCK_SZ + sizeof(fd_vinyl_bstream_phdr_t) + val_max + FD_VINYL_BSTREAM_FTR_SZ
      85             :                         The footprint is a FD_VINYL_BSTREAM_BLOCK_SZ multiple. */
      86             :   ushort obj_cnt;    /* ==num objects in the containing superblock, in [2,64] */
      87             :   ushort parent_szc; /* size class of the superblock that contains objects of this size class,
      88             :                         FD_VINYL_DATA_SZC_CNT indicates superblocks for objects of this size class fill an entire volume,
      89             :                         (the superblock footprint is FD_VINYL_BSTREAM_BLOCK_SZ + obj_cnt*obj_footprint) */
      90             : };
      91             : 
      92             : typedef struct fd_vinyl_data_szc_cfg fd_vinyl_data_szc_cfg_t;
      93             : 
      94             : FD_PROTOTYPES_BEGIN
      95             : 
      96             : /* fd_vinyl_data_szc_cfg describes the sizeclasses used by the data
      97             :    cache.  Indexed [0,FD_VINYL_DATA_SZC_CNT). */
      98             : 
      99    69603471 : #define FD_VINYL_DATA_SZC_CNT (327UL)
     100             : 
     101             : extern fd_vinyl_data_szc_cfg_t const fd_vinyl_data_szc_cfg[ FD_VINYL_DATA_SZC_CNT ];
     102             : 
     103             : /* fd_vinyl_data_szc_obj_footprint returns the in-memory footprint for
     104             :    an object with the given size class.
     105             : 
     106             :    fd_vinyl_data_szc_val_max returns the largest pair val that can be
     107             :    cached in an object with the given size class.  Assumes szc is in
     108             :    [O,FD_VINYL_DATA_SZC_CNT).  Return will be in
     109             :    [0,cfg(SZC_CNT-1).val_max].
     110             : 
     111             :    fd_vinyl_data_szc returns the tightest fitting size class that can
     112             :    cache a pair val with a maximum size of val_max.  Assumes val_max is
     113             :    in [0,szc.cfg(SZC_CNT-1.val_max].  Return will be in
     114             :    [0,FD_VINYL_DATA_SZC_CNT).  The returned size class is typically able
     115             :    to hold a val_max ~1-2% larger than the given val_max.
     116             : 
     117             :    Note that the size classes are configured such that, given val_sz in
     118             :    [0,FD_VINYL_VAL_MAX]:
     119             : 
     120             :      fd_vinyl_data_szc_val_max( fd_vinyl_data_szc( val_sz ) ) <= FD_VINYL_VAL_MAX.
     121             : 
     122             :    where equality is achieved when val_sz==FD_VINYL_VAL_MAX.
     123             : 
     124             :    FIXME: should these be FD_FN_CONST (szc_cfg is const)? */
     125             : 
     126             : FD_FN_PURE static inline ulong
     127    60943713 : fd_vinyl_data_szc_obj_footprint( ulong szc ) {
     128    60943713 :   return FD_VINYL_BSTREAM_BLOCK_SZ +
     129    60943713 :     sizeof(fd_vinyl_bstream_phdr_t) + (ulong)fd_vinyl_data_szc_cfg[ szc ].val_max + FD_VINYL_BSTREAM_FTR_SZ;
     130    60943713 : }
     131             : 
     132             : FD_FN_PURE static inline ulong
     133    42099069 : fd_vinyl_data_szc_val_max( ulong szc ) {
     134    42099069 :   return (ulong)fd_vinyl_data_szc_cfg[ szc ].val_max;
     135    42099069 : }
     136             : 
     137             : FD_FN_PURE static inline ulong
     138    51117102 : fd_vinyl_data_szc( ulong val_max ) {
     139             : 
     140    51117102 :   ulong l = 0UL;
     141    51117102 :   ulong h = FD_VINYL_DATA_SZC_CNT-1UL;
     142             : 
     143   511171020 :   for( ulong rem=9UL; rem; rem-- ) { /* Update if FD_VINYL_DATA_SZC_CNT changed */
     144             : 
     145             :     /* At this point, szc in [0,l) aren't suitable, szc in [h,CNT) are
     146             :        suitable and szc in [l,h) are untested.  See fd_alloc for more
     147             :        detail on using fixed count loop. */
     148             : 
     149   460053918 :     ulong m = (l+h) >> 1;
     150   460053918 :     int   c = (((ulong)fd_vinyl_data_szc_cfg[ m ].val_max) >= val_max);
     151   460053918 :     l = fd_ulong_if( c, l, m+1UL );
     152   460053918 :     h = fd_ulong_if( c, m, h     );
     153             : 
     154   460053918 :   }
     155             : 
     156    51117102 :   return l;
     157    51117102 : }
     158             : 
     159             : FD_PROTOTYPES_END
     160             : 
     161             : /* fd_vinyl_data_obj **************************************************/
     162             : 
     163        7899 : #define FD_VINYL_DATA_OBJ_TYPE_FREEVOL    (0xf7eef7eef7eef7eeUL) /* free, object is a  free volume */
     164    15071136 : #define FD_VINYL_DATA_OBJ_TYPE_ALLOC      (0xa11ca11ca11ca11cUL) /* allc, object is an allocation */
     165     3760572 : #define FD_VINYL_DATA_OBJ_TYPE_SUPERBLOCK (0x59e759e759e759e7UL) /* sper, object is a  superblock */
     166             : 
     167             : #define FD_VINYL_DATA_OBJ_GUARD_SZ (FD_VINYL_BSTREAM_BLOCK_SZ - sizeof(fd_vinyl_io_rd_t) - 8UL*sizeof(ulong))
     168             : 
     169             : struct fd_vinyl_data_obj;
     170             : typedef struct fd_vinyl_data_obj fd_vinyl_data_obj_t;
     171             : 
     172             : struct __attribute__((aligned(FD_VINYL_BSTREAM_BLOCK_SZ))) fd_vinyl_data_obj {
     173             : 
     174             :   /* type gives the object type.  A FD_VINYL_DATA_OBJ_TYPE_*.
     175             : 
     176             :      For type SUPERBLOCK objects, child_szc gives the size class of the
     177             :      objects contained in this superblock.  In
     178             :      [0,FD_VINYL_DATA_SZC_CNT).  Ignored for other types of objects.
     179             : 
     180             :      For type SUPERBLOCK and type ALLOC objects, szc gives the size
     181             :      class of the object.  In [0,FD_VINYL_DATA_SZC_CNT].  Values less
     182             :      then SZC_CNT indicate an object contained in a superblock.  Equal
     183             :      to SZC_CNT indicates an object that fills an entire volume.  For
     184             :      other types of objects, ignored.
     185             : 
     186             :      For objects contained in a parent superblock, idx gives the index
     187             :      of the object in its parent, in [0,szc.obj_cnt).  For objects that
     188             :      fill an entire volume, idx gives the data volume index, in
     189             :      [0,vol_cnt).
     190             : 
     191             :      For type SUPERBLOCK objects, free_blocks gives a bit field
     192             :      identifying which blocks are free.  Ignored for other types of
     193             :      objects.
     194             : 
     195             :      For inactive type SUPERBLOCK objects, next_off gives the byte
     196             :      offset from laddr0 of the next inactive superblock and 0UL if no
     197             :      more inactive superblocks.  next_off is ignored in other
     198             :      circumstances (but see note about pending I/O ops).  Note that this
     199             :      implies laddr0 must less than the local address of vol (such that
     200             :      data gaddr==0 never points to an object).  Note also that, if
     201             :      laddr0 is 0, next_off will be just a pointer in the local address
     202             :      space.
     203             : 
     204             :      Note that I/O acceleration may require memory alignment and I/O
     205             :      device alignment to match.  So we need to put all the object
     206             :      allocator data its own block.  This can leave a lot of extra space.
     207             :      We put this space up front in the block to that it can act as a
     208             :      guard region for whatever preceeds it (applications could even use
     209             :      this guard region to stash extra info but this is not recommended
     210             :      because of false sharing conflicts in might induce between
     211             :      different threads using adjacent in memory objects).  Likewise,
     212             :      because we have all this space from block quantization, we don't
     213             :      try to be hyperefficient with the packing (like we do for, say,
     214             :      fd_alloc). */
     215             : 
     216             : # if 0 /* Note: with BLOCK_SZ==128, GUARD_SZ=0 so there's no guard field due to language limitations */
     217             :   uchar guard[ FD_VINYL_DATA_OBJ_GUARD_SZ ];
     218             : # endif
     219             : 
     220             :   /* rd on its own cache line */
     221             : 
     222             :   fd_vinyl_io_rd_t rd[1]; /* rd: ctx is element idx */
     223             : 
     224             :   /* allocator metadata on its own cache line */
     225             : 
     226             :   ulong   unused[1];   /* unused space */
     227             :   schar * rd_err;      /* rd: client req_err       (or dummy location if no client req_err) */
     228             :   short   rd_active;   /* rd: is a read in progess on this obj */
     229             :   ushort  _unused;     /* unused space */
     230             :   ushort  szc;         /* data: allocation size class */
     231             :   ushort  child_szc;   /* data: (superblock) contains allocations of this sizeclass */
     232             :   ulong   line_idx;    /* vinyl line_idx that is responsible for this object, in [0,line_cnt), ignored if not type alloc */
     233             :   ulong   type;        /* data: allocation type (alloc or superblock) */
     234             :   ulong   idx;         /* data: (alloc or superblock) index of this allocation in its parent superblock, (vol) vol idx */
     235             :   ulong   free_blocks; /* data: (superblock) bit field free allocations */
     236             :   ulong   next_off;    /* data: (inactive superblock) pointer to next inactive superblock or 0 last */
     237             : 
     238             :   /* This point is FD_VINYL_BSTREAM_BLOCK_SZ aligned */
     239             : 
     240             :   /* Space for sizeof(fd_vinyl_bstream_phdr_t) + fd_vinyl_data_szc_cfg[szc].val_max + FD_VINYL_BSTREAM_FTR_SZ
     241             : 
     242             :      Note that is is a FD_VINYL_BSTREAM_BLOCK_SZ multiple so that the
     243             :      entire region starting from phdr can submitted zero copy for
     244             :      streaming to hardware async direct I/O friendly. */
     245             : 
     246             :   /* This point is FD_VINYL_BSTREAM_BLOCK_SZ aligned */
     247             : 
     248             :   /* There is an implied FD_VINYL_DATA_OBJ_GUARD_SZ region here as per
     249             :      note above.  It is not considered part of _this_ data_obj_t though. */
     250             : 
     251             : };
     252             : 
     253             : FD_PROTOTYPES_BEGIN
     254             : 
     255             : /* fd_vinyl_data_obj_* returns a pointer to the eponymous field in
     256             :    the given data object.  Assumes obj is valid.  Returns value for
     257             :    fd_vinyl_data_obj_phdr will be FD_VINYL_BSTREAM_BLOCK_SZ aligned.
     258             :    fd_vinyl_data_* mirror the above but they take the value region as
     259             :    input. */
     260             : 
     261             : FD_FN_CONST static inline fd_vinyl_bstream_phdr_t *
     262     3000000 : fd_vinyl_data_obj_phdr( fd_vinyl_data_obj_t const * obj ) {
     263     3000000 :   return (fd_vinyl_bstream_phdr_t *)((ulong)obj + sizeof(fd_vinyl_data_obj_t));
     264     3000000 : }
     265             : 
     266             : FD_FN_CONST static inline fd_vinyl_key_t *
     267     3000000 : fd_vinyl_data_obj_key( fd_vinyl_data_obj_t const * obj ) {
     268     3000000 :   return (fd_vinyl_key_t *)((ulong)obj + sizeof(fd_vinyl_data_obj_t) + sizeof(ulong));
     269     3000000 : }
     270             : 
     271             : FD_FN_CONST static inline fd_vinyl_info_t *
     272     6000000 : fd_vinyl_data_obj_info( fd_vinyl_data_obj_t const * obj ) {
     273     6000000 :   return (fd_vinyl_info_t *)((ulong)obj + sizeof(fd_vinyl_data_obj_t) + sizeof(ulong) + sizeof(fd_vinyl_key_t));
     274     6000000 : }
     275             : 
     276             : FD_FN_CONST static inline void *
     277     3000000 : fd_vinyl_data_obj_val( fd_vinyl_data_obj_t const * obj ) {
     278     3000000 :   return (void *)((ulong)obj + sizeof(fd_vinyl_data_obj_t) + sizeof(fd_vinyl_bstream_phdr_t));
     279     3000000 : }
     280             : 
     281             : FD_FN_PURE static inline ulong
     282     3000000 : fd_vinyl_data_obj_val_sz( fd_vinyl_data_obj_t const * obj ) {
     283     3000000 :   return (ulong)fd_vinyl_data_obj_info( obj )->val_sz;
     284     3000000 : }
     285             : 
     286             : FD_FN_PURE static inline ulong
     287     3000000 : fd_vinyl_data_obj_val_max( fd_vinyl_data_obj_t const * obj ) {
     288     3000000 :   return fd_vinyl_data_szc_val_max( (ulong)obj->szc );
     289     3000000 : }
     290             : 
     291             : FD_FN_CONST static inline fd_vinyl_data_obj_t *
     292     6000000 : fd_vinyl_data_obj( void const * val ) {
     293     6000000 :   return (fd_vinyl_data_obj_t *)((ulong)val - sizeof(fd_vinyl_bstream_phdr_t) - sizeof(fd_vinyl_data_obj_t));
     294     6000000 : }
     295             : 
     296             : FD_FN_CONST static inline fd_vinyl_bstream_phdr_t *
     297     3000000 : fd_vinyl_data_phdr( void const * val ) {
     298     3000000 :   return (fd_vinyl_bstream_phdr_t *)((ulong)val - sizeof(fd_vinyl_bstream_phdr_t));
     299     3000000 : }
     300             : 
     301             : FD_FN_CONST static inline fd_vinyl_key_t *
     302     3000000 : fd_vinyl_data_key( void const * val ) {
     303     3000000 :   return (fd_vinyl_key_t *)((ulong)val - sizeof(fd_vinyl_info_t) - sizeof(fd_vinyl_key_t));
     304     3000000 : }
     305             : 
     306             : FD_FN_CONST static inline fd_vinyl_info_t *
     307     6000000 : fd_vinyl_data_info( void const * val ) {
     308     6000000 :   return (fd_vinyl_info_t *)((ulong)val - sizeof(fd_vinyl_info_t));
     309     6000000 : }
     310             : 
     311             : FD_FN_PURE static inline ulong
     312     3000000 : fd_vinyl_data_val_sz( void const * val ) {
     313     3000000 :   return (ulong)fd_vinyl_data_info( val )->val_sz;
     314     3000000 : }
     315             : 
     316             : FD_FN_PURE static inline ulong
     317     3000000 : fd_vinyl_data_val_max( void const * val ) {
     318     3000000 :   return fd_vinyl_data_szc_val_max( (ulong)fd_vinyl_data_obj( val )->szc );
     319     3000000 : }
     320             : 
     321             : FD_PROTOTYPES_END
     322             : 
     323             : /* fd_vinyl_data_vol **************************************************/
     324             : 
     325    45793758 : #define FD_VINYL_DATA_VOL_FOOTPRINT (34078592UL) /* autogenerated */
     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    44950959 :                             ulong                       vol_cnt ) {
     411             : 
     412    44950959 :   ulong vol_idx = ((ulong)laddr - (ulong)vol) / FD_VINYL_DATA_VOL_FOOTPRINT;
     413             : 
     414    44950959 :   if( FD_UNLIKELY( !( ((ulong)vol<=(ulong)laddr)                                     &
     415    44950959 :                       (vol_idx<vol_cnt)                                              &
     416    44950959 :                       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    44950959 :   fd_vinyl_data_obj_t const * obj = (fd_vinyl_data_obj_t const *)laddr;
     422    44950959 :   ulong                       szc = (ulong)obj->szc;
     423             : 
     424    44950959 :   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    30000000 :   ulong end = (ulong)laddr + fd_vinyl_data_szc_obj_footprint( szc );
     431             : 
     432    30000000 :   if( FD_UNLIKELY( !((obj->idx<(ulong)fd_vinyl_data_szc_cfg[ szc ].obj_cnt) & (end<=(ulong)&vol[vol_idx+1UL])) ) ) return 0;
     433             : 
     434    30000000 :   return 1;
     435    30000000 : }
     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             : FD_FN_PURE 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 */

Generated by: LCOV version 1.14