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

Generated by: LCOV version 1.14