LCOV - code coverage report
Current view: top level - vinyl/io - fd_vinyl_io_mm.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 363 381 95.3 %
Date: 2025-12-07 04:58:33 Functions: 17 17 100.0 %

          Line data    Source code
       1             : #include "fd_vinyl_io.h"
       2             : 
       3             : struct fd_vinyl_io_mm_rd;
       4             : typedef struct fd_vinyl_io_mm_rd fd_vinyl_io_mm_rd_t;
       5             : 
       6             : struct fd_vinyl_io_mm_rd {
       7             :   ulong                 ctx;  /* Must mirror fd_vinyl_io_rd_t */
       8             :   ulong                 seq;  /* " */
       9             :   void *                dst;  /* " */
      10             :   ulong                 sz;   /* " */
      11             :   fd_vinyl_io_mm_rd_t * next; /* Next element in mm rd queue */
      12             : };
      13             : 
      14             : struct fd_vinyl_io_mm {
      15             :   fd_vinyl_io_t            base[1];
      16             :   uchar *                  dev;          /* Memory mapped I/O memory region */
      17             :   ulong                    dev_sync;     /* Offset to the bstream's sync block (BLOCK_SZ multiple) */
      18             :   ulong                    dev_base;     /* Offset to first block (BLOCK_SZ multiple) */
      19             :   ulong                    dev_sz;       /* Block store byte size (BLOCK_SZ multiple) */
      20             :   fd_vinyl_io_mm_rd_t *    rd_head;      /* Pointer to queue head */
      21             :   fd_vinyl_io_mm_rd_t **   rd_tail_next; /* Pointer to queue &tail->next or &rd_head if empty. */
      22             :   fd_vinyl_bstream_block_t sync[1];
      23             :   /* spad_max bytes follow */
      24             : };
      25             : 
      26             : typedef struct fd_vinyl_io_mm fd_vinyl_io_mm_t;
      27             : 
      28             : static void
      29             : fd_vinyl_io_mm_read_imm( fd_vinyl_io_t * io,
      30             :                          ulong           seq0,
      31             :                          void *          _dst,
      32     1500474 :                          ulong           sz ) {
      33     1500474 :   fd_vinyl_io_mm_t * mm = (fd_vinyl_io_mm_t *)io;  /* Note: io must be non-NULL to have even been called */
      34             : 
      35             :   /* If this is a request to read nothing, succeed immediately.  If
      36             :      this is a request to read outside the bstream's past, fail. */
      37             : 
      38     1500474 :   if( FD_UNLIKELY( !sz ) ) return;
      39             : 
      40     1316775 :   uchar * dst  = (uchar *)_dst;
      41     1316775 :   ulong   seq1 = seq0 + sz;
      42             : 
      43     1316775 :   ulong seq_past    = mm->base->seq_past;
      44     1316775 :   ulong seq_present = mm->base->seq_present;
      45             : 
      46     1316775 :   int bad_seq  = !fd_ulong_is_aligned( seq0, FD_VINYL_BSTREAM_BLOCK_SZ );
      47     1316775 :   int bad_dst  = (!fd_ulong_is_aligned( (ulong)dst, FD_VINYL_BSTREAM_BLOCK_SZ )) | !dst;
      48     1316775 :   int bad_sz   = !fd_ulong_is_aligned( sz,   FD_VINYL_BSTREAM_BLOCK_SZ );
      49     1316775 :   int bad_past = !(fd_vinyl_seq_le( seq_past, seq0 ) & fd_vinyl_seq_lt( seq0, seq1 ) & fd_vinyl_seq_le( seq1, seq_present ));
      50             : 
      51     1316775 :   if( FD_UNLIKELY( bad_seq | bad_dst | bad_sz | bad_past ) )
      52           0 :     FD_LOG_CRIT(( "bstream read_imm [%016lx,%016lx)/%lu failed (past [%016lx,%016lx)/%lu, %s)",
      53     1316775 :                   seq0, seq1, sz, seq_past, seq_present, seq_present-seq_past,
      54     1316775 :                   bad_seq ? "misaligned seq"         :
      55     1316775 :                   bad_dst ? "misaligned or NULL dst" :
      56     1316775 :                   bad_sz  ? "misaligned sz"          :
      57     1316775 :                             "not in past" ));
      58             : 
      59             :   /* At this point, we have a valid read request.  Map seq0 into the
      60             :      bstream store.  Read the lesser of sz bytes or until the store end.
      61             :      If we hit the store end with more to go, wrap around and finish the
      62             :      read at the store start. */
      63             : 
      64     1316775 :   uchar * dev      = mm->dev;
      65     1316775 :   ulong   dev_base = mm->dev_base;
      66     1316775 :   ulong   dev_sz   = mm->dev_sz;
      67             : 
      68     1316775 :   ulong dev_off = seq0 % dev_sz;
      69             : 
      70     1316775 :   ulong rsz = fd_ulong_min( sz, dev_sz - dev_off );
      71     1316775 :   memcpy( dst, dev + dev_base + dev_off, rsz );
      72     1316775 :   sz -= rsz;
      73     1316775 :   if( FD_UNLIKELY( sz ) ) memcpy( dst + rsz, dev + dev_base, sz );
      74     1316775 : }
      75             : 
      76             : static void
      77             : fd_vinyl_io_mm_read( fd_vinyl_io_t *    io,
      78     1873707 :                      fd_vinyl_io_rd_t * _rd ) {
      79     1873707 :   fd_vinyl_io_mm_t *    mm = (fd_vinyl_io_mm_t *)   io;  /* Note: io must be non-NULL to have even been called */
      80     1873707 :   fd_vinyl_io_mm_rd_t * rd = (fd_vinyl_io_mm_rd_t *)_rd;
      81             : 
      82     1873707 :   rd->next          = NULL;
      83     1873707 :   *mm->rd_tail_next = rd;
      84     1873707 :   mm->rd_tail_next  = &rd->next;
      85             : 
      86     1873707 :   ulong   seq0 =          rd->seq;
      87     1873707 :   uchar * dst  = (uchar *)rd->dst;
      88     1873707 :   ulong   sz   =          rd->sz;
      89             : 
      90             :   /* If this is a request to read nothing, succeed immediately.  If
      91             :      this is a request to read outside the bstream's past, fail. */
      92             : 
      93     1873707 :   if( FD_UNLIKELY( !sz ) ) return;
      94             : 
      95     1645263 :   ulong seq1 = seq0 + sz;
      96             : 
      97     1645263 :   ulong seq_past    = mm->base->seq_past;
      98     1645263 :   ulong seq_present = mm->base->seq_present;
      99             : 
     100     1645263 :   int bad_seq  = !fd_ulong_is_aligned( seq0, FD_VINYL_BSTREAM_BLOCK_SZ );
     101     1645263 :   int bad_dst  = (!fd_ulong_is_aligned( (ulong)dst, FD_VINYL_BSTREAM_BLOCK_SZ )) | !dst;
     102     1645263 :   int bad_sz   = !fd_ulong_is_aligned( sz,   FD_VINYL_BSTREAM_BLOCK_SZ );
     103     1645263 :   int bad_past = !(fd_vinyl_seq_le( seq_past, seq0 ) & fd_vinyl_seq_lt( seq0, seq1 ) & fd_vinyl_seq_le( seq1, seq_present ));
     104             : 
     105     1645263 :   if( FD_UNLIKELY( bad_seq | bad_dst | bad_sz | bad_past ) )
     106           0 :     FD_LOG_CRIT(( "bstream read [%016lx,%016lx)/%lu failed (past [%016lx,%016lx)/%lu, %s)",
     107     1645263 :                   seq0, seq1, sz, seq_past, seq_present, seq_present-seq_past,
     108     1645263 :                   bad_seq ? "misaligned seq"         :
     109     1645263 :                   bad_dst ? "misaligned or NULL dst" :
     110     1645263 :                   bad_sz  ? "misaligned sz"          :
     111     1645263 :                             "not in past" ));
     112             : 
     113             :   /* At this point, we have a valid read request.  Map seq0 into the
     114             :      bstream store.  Read the lesser of sz bytes or until the store end.
     115             :      If we hit the store end with more to go, wrap around and finish the
     116             :      read at the store start. */
     117             : 
     118     1645263 :   uchar const * dev      = mm->dev;
     119     1645263 :   ulong         dev_base = mm->dev_base;
     120     1645263 :   ulong         dev_sz   = mm->dev_sz;
     121             : 
     122     1645263 :   ulong dev_off = seq0 % dev_sz;
     123             : 
     124     1645263 :   ulong rsz = fd_ulong_min( sz, dev_sz - dev_off );
     125     1645263 :   memcpy( dst, dev + dev_base + dev_off, rsz );
     126     1645263 :   sz -= rsz;
     127     1645263 :   if( FD_UNLIKELY( sz ) ) memcpy( dst + rsz, dev + dev_base, sz );
     128     1645263 : }
     129             : 
     130             : static int
     131             : fd_vinyl_io_mm_poll( fd_vinyl_io_t *     io,
     132             :                      fd_vinyl_io_rd_t ** _rd,
     133     3747414 :                      int                 flags ) {
     134     3747414 :   fd_vinyl_io_mm_t * mm = (fd_vinyl_io_mm_t * )io; /* Note: io must be non-NULL to have even been called */
     135     3747414 :   (void)flags;
     136             : 
     137     3747414 :   fd_vinyl_io_mm_rd_t *  rd = mm->rd_head;
     138             : 
     139     3747414 :   if( FD_UNLIKELY( !rd ) ) {
     140     1873707 :     *_rd = NULL;
     141     1873707 :     return FD_VINYL_ERR_EMPTY;
     142     1873707 :   }
     143             : 
     144     1873707 :   fd_vinyl_io_mm_rd_t ** rd_tail_next = mm->rd_tail_next;
     145     1873707 :   fd_vinyl_io_mm_rd_t *  rd_next      = rd->next;
     146             : 
     147     1873707 :   mm->rd_head      = rd_next;
     148     1873707 :   mm->rd_tail_next = fd_ptr_if( !!rd_next, rd_tail_next, &mm->rd_head );
     149             : 
     150     1873707 :   *_rd = (fd_vinyl_io_rd_t *)rd;
     151     1873707 :   return FD_VINYL_SUCCESS;
     152     3747414 : }
     153             : 
     154             : static ulong
     155             : fd_vinyl_io_mm_append( fd_vinyl_io_t * io,
     156             :                        void const *    _src,
     157      374868 :                        ulong           sz ) {
     158      374868 :   fd_vinyl_io_mm_t * mm  = (fd_vinyl_io_mm_t *)io; /* Note: io must be non-NULL to have even been called */
     159      374868 :   uchar const *      src = (uchar const *)_src;
     160             : 
     161             :   /* Validate the input args. */
     162             : 
     163      374868 :   ulong   seq_future  = mm->base->seq_future;  if( FD_UNLIKELY( !sz ) ) return seq_future;
     164      374868 :   ulong   seq_ancient = mm->base->seq_ancient;
     165      374868 :   uchar * dev         = mm->dev;
     166      374868 :   ulong   dev_base    = mm->dev_base;
     167      374868 :   ulong   dev_sz      = mm->dev_sz;
     168             : 
     169      374868 :   int bad_src      = !src;
     170      374868 :   int bad_align    = !fd_ulong_is_aligned( (ulong)src, FD_VINYL_BSTREAM_BLOCK_SZ );
     171      374868 :   int bad_sz       = !fd_ulong_is_aligned( sz,         FD_VINYL_BSTREAM_BLOCK_SZ );
     172      374868 :   int bad_capacity = sz > (dev_sz - (seq_future-seq_ancient));
     173             : 
     174      374868 :   if( FD_UNLIKELY( bad_src | bad_align | bad_sz | bad_capacity ) )
     175           0 :     FD_LOG_CRIT(( bad_src   ? "NULL src"       :
     176      374868 :                   bad_align ? "misaligned src" :
     177      374868 :                   bad_sz    ? "misaligned sz"  :
     178      374868 :                               "device full" ));
     179             : 
     180             :   /* At this point, we appear to have a valid append request.  Map it to
     181             :      the bstream (updating seq_future) and map it to the device.  Then
     182             :      write the lesser of sz bytes or until the store end.  If we hit the
     183             :      store end with more to go, wrap around and finish the write at the
     184             :      store start. */
     185             : 
     186      374868 :   ulong seq = seq_future;
     187      374868 :   mm->base->seq_future = seq + sz;
     188             : 
     189      374868 :   ulong dev_off = seq % dev_sz;
     190             : 
     191      374868 :   ulong wsz = fd_ulong_min( sz, dev_sz - dev_off );
     192      374868 :   memcpy( dev + dev_base + dev_off, src, wsz );
     193      374868 :   sz -= wsz;
     194      374868 :   if( sz ) memcpy( dev + dev_base, src + wsz, sz );
     195             : 
     196      374868 :   return seq;
     197      374868 : }
     198             : 
     199             : static int
     200             : fd_vinyl_io_mm_commit( fd_vinyl_io_t * io,
     201      374532 :                        int             flags ) {
     202      374532 :   fd_vinyl_io_mm_t * mm = (fd_vinyl_io_mm_t *)io; /* Note: io must be non-NULL to have even been called */
     203      374532 :   (void)flags;
     204             : 
     205      374532 :   mm->base->seq_present = mm->base->seq_future;
     206      374532 :   mm->base->spad_used   = 0UL;
     207             : 
     208      374532 :   return FD_VINYL_SUCCESS;
     209      374532 : }
     210             : 
     211             : static ulong
     212             : fd_vinyl_io_mm_hint( fd_vinyl_io_t * io,
     213      376362 :                      ulong           sz ) {
     214      376362 :   fd_vinyl_io_mm_t * mm = (fd_vinyl_io_mm_t *)io; /* Note: io must be non-NULL to have even been called */
     215             : 
     216      376362 :   ulong seq_future  = mm->base->seq_future;  if( FD_UNLIKELY( !sz ) ) return seq_future;
     217      376362 :   ulong seq_ancient = mm->base->seq_ancient;
     218      376362 :   ulong dev_sz      = mm->dev_sz;
     219             : 
     220      376362 :   int bad_sz       = !fd_ulong_is_aligned( sz, FD_VINYL_BSTREAM_BLOCK_SZ );
     221      376362 :   int bad_capacity = sz > (dev_sz - (seq_future-seq_ancient));
     222             : 
     223      376362 :   if( FD_UNLIKELY( bad_sz | bad_capacity ) ) FD_LOG_CRIT(( bad_sz ? "misaligned sz" : "device full" ));
     224             : 
     225      376362 :   return mm->base->seq_future;
     226      376362 : }
     227             : 
     228             : static void *
     229             : fd_vinyl_io_mm_alloc( fd_vinyl_io_t * io,
     230             :                       ulong           sz,
     231         363 :                       int             flags ) {
     232         363 :   fd_vinyl_io_mm_t * mm = (fd_vinyl_io_mm_t *)io; /* Note: io must be non-NULL to have even been called */
     233             : 
     234         363 :   ulong spad_max  = mm->base->spad_max;
     235         363 :   ulong spad_used = mm->base->spad_used; if( FD_UNLIKELY( !sz ) ) return ((uchar *)(mm+1)) + spad_used;
     236             : 
     237         363 :   int bad_align = !fd_ulong_is_aligned( sz, FD_VINYL_BSTREAM_BLOCK_SZ );
     238         363 :   int bad_sz    = sz > spad_max;
     239             : 
     240         363 :   if( FD_UNLIKELY( bad_align | bad_sz ) ) FD_LOG_CRIT(( bad_align ? "misaligned sz" : "sz too large" ));
     241             : 
     242         363 :   if( FD_UNLIKELY( sz > (spad_max - spad_used ) ) ) {
     243           0 :     if( FD_UNLIKELY( fd_vinyl_io_mm_commit( io, flags ) ) ) return NULL;
     244           0 :     spad_used = 0UL;
     245           0 :   }
     246             : 
     247         363 :   mm->base->spad_used = spad_used + sz;
     248             : 
     249         363 :   return ((uchar *)(mm+1)) + spad_used;
     250         363 : }
     251             : 
     252             : static ulong
     253             : fd_vinyl_io_mm_copy( fd_vinyl_io_t * io,
     254             :                      ulong           seq_src0,
     255      376227 :                      ulong           sz ) {
     256      376227 :   fd_vinyl_io_mm_t * mm = (fd_vinyl_io_mm_t *)io; /* Note: io must be non-NULL to have even been called */
     257             : 
     258             :   /* Validate the input args */
     259             : 
     260      376227 :   ulong   seq_ancient = mm->base->seq_ancient;
     261      376227 :   ulong   seq_past    = mm->base->seq_past;
     262      376227 :   ulong   seq_present = mm->base->seq_present;
     263      376227 :   ulong   seq_future  = mm->base->seq_future;   if( FD_UNLIKELY( !sz ) ) return seq_future;
     264      330246 :   ulong   spad_max    = mm->base->spad_max;
     265      330246 :   ulong   spad_used   = mm->base->spad_used;
     266      330246 :   uchar * dev         = mm->dev;
     267      330246 :   ulong   dev_base    = mm->dev_base;
     268      330246 :   ulong   dev_sz      = mm->dev_sz;
     269             : 
     270      330246 :   ulong seq_src1 = seq_src0 + sz;
     271             : 
     272      330246 :   int bad_past     = !( fd_vinyl_seq_le( seq_past, seq_src0    ) &
     273      330246 :                         fd_vinyl_seq_lt( seq_src0, seq_src1    ) &
     274      330246 :                         fd_vinyl_seq_le( seq_src1, seq_present ) );
     275      330246 :   int bad_src      = !fd_ulong_is_aligned( seq_src0, FD_VINYL_BSTREAM_BLOCK_SZ );
     276      330246 :   int bad_sz       = !fd_ulong_is_aligned( sz,       FD_VINYL_BSTREAM_BLOCK_SZ );
     277      330246 :   int bad_capacity = sz > (dev_sz - (seq_future-seq_ancient));
     278             : 
     279      330246 :   if( FD_UNLIKELY( bad_past | bad_src | bad_sz | bad_capacity ) )
     280           0 :     FD_LOG_CRIT(( bad_past ? "src is not in the past"    :
     281      330246 :                   bad_src  ? "misaligned src_seq"        :
     282      330246 :                   bad_sz   ? "misaligned sz"             :
     283      330246 :                              "device full" ));
     284             : 
     285             :   /* At this point, we appear to have a valid copy request.  Get
     286             :      buffer space from the scratch pad (committing as necessary). */
     287             : 
     288      330246 :   if( FD_UNLIKELY( sz>(spad_max-spad_used) ) ) {
     289           0 :     fd_vinyl_io_mm_commit( io, FD_VINYL_IO_FLAG_BLOCKING );
     290           0 :     spad_used = 0UL;
     291           0 :   }
     292             : 
     293      330246 :   uchar * buf     = (uchar *)(mm+1) + spad_used;
     294      330246 :   ulong   buf_max = spad_max - spad_used;
     295             : 
     296             :   /* Map the dst to the bstream (updating seq_future) and map the src
     297             :      and dst regions onto the device.  Then copy as much as we can at a
     298             :      time, handling device wrap around and copy buffering space. */
     299             : 
     300      330246 :   ulong seq = seq_future;
     301      330246 :   mm->base->seq_future = seq + sz;
     302             : 
     303      330246 :   ulong seq_dst0 = seq;
     304             : 
     305      330273 :   for(;;) {
     306      330273 :     ulong src_off = seq_src0 % dev_sz;
     307      330273 :     ulong dst_off = seq_dst0 % dev_sz;
     308      330273 :     ulong csz     = fd_ulong_min( fd_ulong_min( sz, buf_max ), fd_ulong_min( dev_sz - src_off, dev_sz - dst_off ) );
     309             : 
     310      330273 :     memcpy( buf, dev + dev_base + src_off, csz );
     311      330273 :     memcpy( dev + dev_base + dst_off, buf, csz );
     312             : 
     313      330273 :     sz -= csz;
     314      330273 :     if( !sz ) break;
     315             : 
     316          27 :     seq_src0 += csz;
     317          27 :     seq_dst0 += csz;
     318          27 :   }
     319             : 
     320      330246 :   return seq;
     321      330246 : }
     322             : 
     323             : static void
     324             : fd_vinyl_io_mm_forget( fd_vinyl_io_t * io,
     325      133263 :                        ulong           seq ) {
     326      133263 :   fd_vinyl_io_mm_t * mm = (fd_vinyl_io_mm_t *)io; /* Note: io must be non-NULL to have even been called */
     327             : 
     328             :   /* Validate input arguments.  Note that we don't allow forgetting into
     329             :      the future even when we have no uncommitted blocks because the
     330             :      resulting [seq_ancient,seq_future) might contain blocks that were
     331             :      never written (which might not be an issue practically but it would
     332             :      be a bit strange for something to try to scan starting from
     333             :      seq_ancient and discover unwritten blocks). */
     334             : 
     335      133263 :   ulong seq_past    = mm->base->seq_past;
     336      133263 :   ulong seq_present = mm->base->seq_present;
     337      133263 :   ulong seq_future  = mm->base->seq_future;
     338             : 
     339      133263 :   int bad_seq    = !fd_ulong_is_aligned( seq, FD_VINYL_BSTREAM_BLOCK_SZ );
     340      133263 :   int bad_dir    = !(fd_vinyl_seq_le( seq_past, seq ) & fd_vinyl_seq_le( seq, seq_present ));
     341      133263 :   int bad_read   = !!mm->rd_head;
     342      133263 :   int bad_append = fd_vinyl_seq_ne( seq_present, seq_future );
     343             : 
     344      133263 :   if( FD_UNLIKELY( bad_seq | bad_dir | bad_read | bad_append ) )
     345           0 :     FD_LOG_CRIT(( "forget to seq %016lx failed (past [%016lx,%016lx)/%lu, %s)",
     346      133263 :                   seq, seq_past, seq_present, seq_present-seq_past,
     347      133263 :                   bad_seq  ? "misaligned seq"             :
     348      133263 :                   bad_dir  ? "seq out of bounds"          :
     349      133263 :                   bad_read ? "reads in progress"          :
     350      133263 :                              "appends/copies in progress" ));
     351             : 
     352      133263 :   mm->base->seq_past = seq;
     353      133263 : }
     354             : 
     355             : static void
     356             : fd_vinyl_io_mm_rewind( fd_vinyl_io_t * io,
     357      132108 :                        ulong           seq ) {
     358      132108 :   fd_vinyl_io_mm_t * mm = (fd_vinyl_io_mm_t *)io; /* Note: io must be non-NULL to have even been called */
     359             : 
     360             :   /* Validate input argments.  Unlike forgot, we do allow rewinding to
     361             :      before seq_ancient as the region of sequence space reported to the
     362             :      caller as written is still accurate. */
     363             : 
     364      132108 :   ulong seq_ancient = mm->base->seq_ancient;
     365      132108 :   ulong seq_past    = mm->base->seq_past;
     366      132108 :   ulong seq_present = mm->base->seq_present;
     367      132108 :   ulong seq_future  = mm->base->seq_future;
     368             : 
     369      132108 :   int bad_seq    = !fd_ulong_is_aligned( seq, FD_VINYL_BSTREAM_BLOCK_SZ );
     370      132108 :   int bad_dir    = fd_vinyl_seq_gt( seq, seq_present );
     371      132108 :   int bad_read   = !!mm->rd_head;
     372      132108 :   int bad_append = fd_vinyl_seq_ne( seq_present, seq_future );
     373             : 
     374      132108 :   if( FD_UNLIKELY( bad_seq | bad_dir | bad_read | bad_append ) )
     375           0 :     FD_LOG_CRIT(( "rewind to seq %016lx failed (present %016lx, %s)", seq, seq_present,
     376      132108 :                   bad_seq  ? "misaligned seq"             :
     377      132108 :                   bad_dir  ? "seq after seq_present"      :
     378      132108 :                   bad_read ? "reads in progress"          :
     379      132108 :                              "appends/copies in progress" ));
     380             : 
     381      132108 :   mm->base->seq_ancient = fd_ulong_if( fd_vinyl_seq_ge( seq, seq_ancient ), seq_ancient, seq );
     382      132108 :   mm->base->seq_past    = fd_ulong_if( fd_vinyl_seq_ge( seq, seq_past    ), seq_past,    seq );
     383      132108 :   mm->base->seq_present = seq;
     384      132108 :   mm->base->seq_future  = seq;
     385      132108 : }
     386             : 
     387             : static int
     388             : fd_vinyl_io_mm_sync( fd_vinyl_io_t * io,
     389      374442 :                      int             flags ) {
     390      374442 :   fd_vinyl_io_mm_t * mm = (fd_vinyl_io_mm_t *)io; /* Note: io must be non-NULL to have even been called */
     391      374442 :   (void)flags;
     392             : 
     393      374442 :   ulong   seed        = mm->base->seed;
     394      374442 :   ulong   seq_past    = mm->base->seq_past;
     395      374442 :   ulong   seq_present = mm->base->seq_present;
     396      374442 :   uchar * dev         = mm->dev;
     397      374442 :   ulong   dev_sync    = mm->dev_sync;
     398             : 
     399      374442 :   fd_vinyl_bstream_block_t * block = mm->sync;
     400             : 
     401             :   /* block->sync.ctl     current (static) */
     402      374442 :   block->sync.seq_past    = seq_past;
     403      374442 :   block->sync.seq_present = seq_present;
     404             :   /* block->sync.info_sz current (static) */
     405             :   /* block->sync.info    current (static) */
     406             : 
     407      374442 :   block->sync.hash_trail  = 0UL;
     408      374442 :   block->sync.hash_blocks = 0UL;
     409      374442 :   fd_vinyl_bstream_block_hash( seed, block ); /* sets hash_trail back to seed */
     410             : 
     411      374442 :   memcpy( dev + dev_sync, block, FD_VINYL_BSTREAM_BLOCK_SZ );
     412             : 
     413      374442 :   mm->base->seq_ancient = seq_past;
     414             : 
     415      374442 :   return FD_VINYL_SUCCESS;
     416      374442 : }
     417             : 
     418             : static void *
     419           6 : fd_vinyl_io_mm_fini( fd_vinyl_io_t * io ) {
     420           6 :   fd_vinyl_io_mm_t * mm = (fd_vinyl_io_mm_t *)io; /* Note: io must be non-NULL to have even been called */
     421             : 
     422           6 :   ulong seq_present = mm->base->seq_present;
     423           6 :   ulong seq_future  = mm->base->seq_future;
     424             : 
     425           6 :   if( FD_UNLIKELY( mm->rd_head                                ) ) FD_LOG_WARNING(( "fini completing outstanding reads" ));
     426           6 :   if( FD_UNLIKELY( fd_vinyl_seq_ne( seq_present, seq_future ) ) ) FD_LOG_WARNING(( "fini discarding uncommited blocks" ));
     427             : 
     428           6 :   return io;
     429           6 : }
     430             : 
     431             : static fd_vinyl_io_impl_t fd_vinyl_io_mm_impl[1] = { {
     432             :   fd_vinyl_io_mm_read_imm,
     433             :   fd_vinyl_io_mm_read,
     434             :   fd_vinyl_io_mm_poll,
     435             :   fd_vinyl_io_mm_append,
     436             :   fd_vinyl_io_mm_commit,
     437             :   fd_vinyl_io_mm_hint,
     438             :   fd_vinyl_io_mm_alloc,
     439             :   fd_vinyl_io_mm_copy,
     440             :   fd_vinyl_io_mm_forget,
     441             :   fd_vinyl_io_mm_rewind,
     442             :   fd_vinyl_io_mm_sync,
     443             :   fd_vinyl_io_mm_fini
     444             : } };
     445             : 
     446             : FD_STATIC_ASSERT( alignof(fd_vinyl_io_mm_t)==FD_VINYL_BSTREAM_BLOCK_SZ, layout );
     447             : 
     448             : ulong
     449          39 : fd_vinyl_io_mm_align( void ) {
     450          39 :   return alignof(fd_vinyl_io_mm_t);
     451          39 : }
     452             : 
     453             : ulong
     454          39 : fd_vinyl_io_mm_footprint( ulong spad_max ) {
     455          39 :   if( FD_UNLIKELY( !((0UL<spad_max) & (spad_max<(1UL<<63)) & fd_ulong_is_aligned( spad_max, FD_VINYL_BSTREAM_BLOCK_SZ )) ) )
     456          12 :     return 0UL;
     457          27 :   return sizeof(fd_vinyl_io_mm_t) + spad_max;
     458          39 : }
     459             : 
     460             : fd_vinyl_io_t *
     461             : fd_vinyl_io_mm_init( void *       mem,
     462             :                      ulong        spad_max,
     463             :                      void *       dev,
     464             :                      ulong        dev_sz,
     465             :                      int          reset,
     466             :                      void const * info,
     467             :                      ulong        info_sz,
     468          39 :                      ulong        io_seed ) {
     469          39 :   fd_vinyl_io_mm_t * mm = (fd_vinyl_io_mm_t *)mem;
     470             : 
     471          39 :   if( FD_UNLIKELY( !mm ) ) {
     472           3 :     FD_LOG_WARNING(( "NULL mem" ));
     473           3 :     return NULL;
     474           3 :   }
     475             : 
     476          36 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mm, fd_vinyl_io_mm_align() ) ) ) {
     477           3 :     FD_LOG_WARNING(( "misaligned mem" ));
     478           3 :     return NULL;
     479           3 :   }
     480             : 
     481          33 :   ulong footprint = fd_vinyl_io_mm_footprint( spad_max );
     482          33 :   if( FD_UNLIKELY( !footprint ) ) {
     483           9 :     FD_LOG_WARNING(( "bad spad_max" ));
     484           9 :     return NULL;
     485           9 :   }
     486             : 
     487          24 :   if( FD_UNLIKELY( !dev ) ) {
     488           3 :     FD_LOG_WARNING(( "NULL dev" ));
     489           3 :     return NULL;
     490           3 :   }
     491             : 
     492          21 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)dev, FD_VINYL_BSTREAM_BLOCK_SZ ) ) ) {
     493           3 :     FD_LOG_WARNING(( "misaligned mem" ));
     494           3 :     return NULL;
     495           3 :   }
     496             : 
     497          18 :   ulong dev_sz_min = 3UL*FD_VINYL_BSTREAM_BLOCK_SZ /* sync block, move block, closing partition */
     498          18 :                    + fd_vinyl_bstream_pair_sz( FD_VINYL_VAL_MAX ); /* worst case pair (FIXME: LZ4_COMPRESSBOUND?) */
     499             : 
     500          18 :   int too_small  = dev_sz < dev_sz_min;
     501          18 :   int too_large  = dev_sz > (ulong)LONG_MAX;
     502          18 :   int misaligned = !fd_ulong_is_aligned( dev_sz, FD_VINYL_BSTREAM_BLOCK_SZ );
     503             : 
     504          18 :   if( FD_UNLIKELY( too_small | too_large | misaligned ) ) {
     505           6 :     FD_LOG_WARNING(( "bstream size %s", too_small ? "too small" :
     506           6 :                                         too_large ? "too large" :
     507           6 :                                                     "not a block size multiple" ));
     508           6 :     return NULL;
     509           6 :   }
     510             : 
     511          12 :   if( reset ) {
     512           6 :     if( FD_UNLIKELY( !info ) ) info_sz = 0UL;
     513           6 :     if( FD_UNLIKELY( info_sz>FD_VINYL_BSTREAM_SYNC_INFO_MAX ) ) {
     514           3 :       FD_LOG_WARNING(( "info_sz too large" ));
     515           3 :       return NULL;
     516           3 :     }
     517           6 :   }
     518             : 
     519           9 :   memset( mm, 0, footprint );
     520             : 
     521           9 :   mm->base->type = FD_VINYL_IO_TYPE_MM;
     522             : 
     523             :   /* io_seed, seq_ancient, seq_past, seq_present, seq_future are init
     524             :      below */
     525             : 
     526           9 :   mm->base->spad_max  = spad_max;
     527           9 :   mm->base->spad_used = 0UL;
     528           9 :   mm->base->impl      = fd_vinyl_io_mm_impl;
     529             : 
     530           9 :   mm->dev      = dev;
     531           9 :   mm->dev_sync = 0UL;                            /* Use the beginning of the file for the sync block */
     532           9 :   mm->dev_base = FD_VINYL_BSTREAM_BLOCK_SZ;      /* Use the rest for the actual bstream store (at least 4) */
     533           9 :   mm->dev_sz   = dev_sz - FD_VINYL_BSTREAM_BLOCK_SZ;
     534             : 
     535           9 :   mm->rd_head      = NULL;
     536           9 :   mm->rd_tail_next = &mm->rd_head;
     537             : 
     538             :   /* Note that [seq_ancient,seq_future) (cyclic) contains at most dev_sz
     539             :      bytes, bstream's antiquity, past and present are subsets of this
     540             :      range and dev_sz is less than 2^63 given the above (practically
     541             :      much much less).  As such, differences between two ordered bstream
     542             :      sequence numbers (e.g. ulong sz = seq_a - seq_b where a is
     543             :      logically not before b) will "just work" regardless of wrapping
     544             :      and/or amount of data stored. */
     545             : 
     546           9 :   fd_vinyl_bstream_block_t * block = mm->sync;
     547             : 
     548           9 :   if( reset ) {
     549             : 
     550             :     /* We are starting a new bstream.  Write the initial sync block. */
     551             : 
     552           3 :     mm->base->seed        = io_seed;
     553           3 :     mm->base->seq_ancient = 0UL;
     554           3 :     mm->base->seq_past    = 0UL;
     555           3 :     mm->base->seq_present = 0UL;
     556           3 :     mm->base->seq_future  = 0UL;
     557             : 
     558           3 :     memset( block, 0, FD_VINYL_BSTREAM_BLOCK_SZ ); /* bulk zero */
     559             : 
     560           3 :     block->sync.ctl         = fd_vinyl_bstream_ctl( FD_VINYL_BSTREAM_CTL_TYPE_SYNC, 0, FD_VINYL_VAL_MAX );
     561             :   //block->sync.seq_past    = ...; /* init by sync */
     562             :   //block->sync.seq_present = ...; /* init by sync */
     563           3 :     block->sync.info_sz     = info_sz;
     564           3 :     if( info_sz ) memcpy( block->sync.info, info, info_sz );
     565             :   //block->sync.hash_trail  = ...; /* init by sync */
     566             :   //block->sync.hash_blocks = ...; /* init by sync */
     567             : 
     568           3 :     int err = fd_vinyl_io_mm_sync( mm->base, FD_VINYL_IO_FLAG_BLOCKING ); /* logs details */
     569           3 :     if( FD_UNLIKELY( err ) ) {
     570           0 :       FD_LOG_WARNING(( "sync block write failed (%i-%s)", err, fd_vinyl_strerror( err ) ));
     571           0 :       return NULL;
     572           0 :     }
     573             : 
     574           6 :   } else {
     575             : 
     576             :     /* We are resuming an existing bstream.  Read and validate the
     577             :        bstream's sync block. */
     578             : 
     579           6 :     memcpy( block, mm->dev + mm->dev_sync, FD_VINYL_BSTREAM_BLOCK_SZ ); /* logs details */
     580             : 
     581           6 :     int   type        = fd_vinyl_bstream_ctl_type ( block->sync.ctl );
     582           6 :     int   version     = fd_vinyl_bstream_ctl_style( block->sync.ctl );
     583           6 :     ulong val_max     = fd_vinyl_bstream_ctl_sz   ( block->sync.ctl );
     584           6 :     ulong seq_past    = block->sync.seq_past;
     585           6 :     ulong seq_present = block->sync.seq_present;
     586           6 :     /**/  info_sz     = block->sync.info_sz;    // overrides user info_sz
     587           6 :     /**/  info        = block->sync.info;       // overrides user info
     588           6 :     /**/  io_seed     = block->sync.hash_trail; // overrides user io_seed
     589             : 
     590           6 :     int bad_type        = (type != FD_VINYL_BSTREAM_CTL_TYPE_SYNC);
     591           6 :     int bad_version     = (version != 0);
     592           6 :     int bad_val_max     = (val_max != FD_VINYL_VAL_MAX);
     593           6 :     int bad_seq_past    = !fd_ulong_is_aligned( seq_past,    FD_VINYL_BSTREAM_BLOCK_SZ );
     594           6 :     int bad_seq_present = !fd_ulong_is_aligned( seq_present, FD_VINYL_BSTREAM_BLOCK_SZ );
     595           6 :     int bad_info_sz     = (info_sz > FD_VINYL_BSTREAM_SYNC_INFO_MAX);
     596           6 :     int bad_past_order  = fd_vinyl_seq_gt( seq_past, seq_present );
     597           6 :     int bad_past_sz     = ((seq_present-seq_past) > mm->dev_sz);
     598             : 
     599           6 :     if( FD_UNLIKELY( bad_type | bad_version | bad_val_max | bad_seq_past | bad_seq_present | bad_info_sz |
     600           6 :                      bad_past_order | bad_past_sz ) ) {
     601           3 :       FD_LOG_WARNING(( "bad sync block when recovering (%s)",
     602           3 :                        bad_type        ? "unexpected type"                             :
     603           3 :                        bad_version     ? "unexpected version"                          :
     604           3 :                        bad_val_max     ? "unexpected max pair value decoded byte size" :
     605           3 :                        bad_seq_past    ? "unaligned seq_past"                          :
     606           3 :                        bad_seq_present ? "unaligned seq_present"                       :
     607           3 :                        bad_info_sz     ? "unexpected info size"                        :
     608           3 :                        bad_past_order  ? "unordered seq_past and seq_present"          :
     609           3 :                                          "past size larger than bstream store" ));
     610           3 :       return NULL;
     611           3 :     }
     612             : 
     613           3 :     if( FD_UNLIKELY( fd_vinyl_bstream_block_test( io_seed, block ) ) ) {
     614           0 :       FD_LOG_WARNING(( "corrupt sync block when recovering bstream store" ));
     615           0 :       return NULL;
     616           0 :     }
     617             : 
     618           3 :     mm->base->seed        = io_seed;
     619           3 :     mm->base->seq_ancient = seq_past;
     620           3 :     mm->base->seq_past    = seq_past;
     621           3 :     mm->base->seq_present = seq_present;
     622           3 :     mm->base->seq_future  = seq_present;
     623             : 
     624           3 :   }
     625             : 
     626           6 :   FD_LOG_NOTICE(( "IO config"
     627           6 :                   "\n\ttype     mm"
     628           6 :                   "\n\tspad_max %lu bytes"
     629           6 :                   "\n\tdev_sz   %lu bytes"
     630           6 :                   "\n\treset    %i"
     631           6 :                   "\n\tinfo     \"%s\" (info_sz %lu%s)"
     632           6 :                   "\n\tio_seed  0x%016lx%s",
     633           6 :                   spad_max, dev_sz, reset,
     634           6 :                   info ? (char const *)info : "", info_sz, reset ? "" : ", discovered",
     635           6 :                   io_seed, reset ? "" : " (discovered)" ));
     636             : 
     637           6 :   return mm->base;
     638           9 : }
     639             : 
     640             : void *
     641           6 : fd_vinyl_mmio( fd_vinyl_io_t * io ) {
     642           6 :   if( FD_UNLIKELY( io->type!=FD_VINYL_IO_TYPE_MM ) ) return NULL;
     643           3 :   fd_vinyl_io_mm_t * mm = (fd_vinyl_io_mm_t *)io;
     644           3 :   return mm->dev + mm->dev_base;
     645           6 : }
     646             : 
     647             : ulong
     648           6 : fd_vinyl_mmio_sz( fd_vinyl_io_t * io ) {
     649           6 :   if( FD_UNLIKELY( io->type!=FD_VINYL_IO_TYPE_MM ) ) return 0UL;
     650           3 :   fd_vinyl_io_mm_t * mm = (fd_vinyl_io_mm_t *)io;
     651           3 :   return mm->dev_sz;
     652           6 : }

Generated by: LCOV version 1.14