LCOV - code coverage report
Current view: top level - vinyl/data - fd_vinyl_data.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 75 75 100.0 %
Date: 2026-09-17 04:28:31 Functions: 20 190 10.5 %

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

Generated by: LCOV version 1.14