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

Generated by: LCOV version 1.14