LCOV - code coverage report
Current view: top level - discof/backup - fd_snapzp_tile.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 515 0.0 %
Date: 2026-08-15 04:34:25 Functions: 0 20 0.0 %

          Line data    Source code
       1             : /* The snapzp tile gathers account data, compresses it, and writes it to
       2             :    disk.
       3             : 
       4             :    It has two modes:
       5             :    - cache: resolve account pointers from in-memory DB cache (fall back
       6             :             to disk on overrun)
       7             :    - disk:  recover accounts from streaming disk reads (from snaprd)
       8             : 
       9             :    Internally, snapzp does streaming compression from DRAM into tile
      10             :    scratch memory.  Whenever compression scratch buffer fills, it is
      11             :    prepended on-the-fly with a matching compressed TAR header.  Finally,
      12             :    everything is written to disk. */
      13             : 
      14             : #define _GNU_SOURCE
      15             : #define ZSTD_STATIC_LINKING_ONLY
      16             : #include <zstd.h>
      17             : #include "fd_backup.h"
      18             : #include "fd_backup_cache.h"
      19             : #include "fd_backup_shmem.h"
      20             : #include "../../disco/metrics/fd_metrics.h"
      21             : #include "../../disco/stem/fd_stem.h"
      22             : #include "../../disco/topo/fd_topo.h"
      23             : 
      24             : #include <time.h> /* CLOCK_REALTIME */
      25             : #include "generated/fd_snapzp_tile_seccomp.h"
      26             : #include "../../tango/fseq/fd_fseq.h"
      27             : #include <fcntl.h>
      28             : #include <unistd.h>
      29             : #include <errno.h>
      30             : 
      31           0 : #define FD_ZSTD_LEVEL 1
      32             : 
      33             : /* Compression buffer params */
      34           0 : #define RAW_BUF_SZ    (32UL<<20) /* FIXME make this configurable */
      35             : #define COMP_BOUND    ZSTD_COMPRESSBOUND( RAW_BUF_SZ )
      36           0 : #define COMP_HEAD     522 /* 10 byte Zstandard uncompressed header + 512 byte plaintext tar header */
      37           0 : #define COMP_BUF_SZ   FD_ULONG_ALIGN_UP( COMP_HEAD+COMP_BOUND+8UL, 4096UL )
      38             : 
      39             : struct fd_snapzp {
      40             :   fd_backup_cache_t  acc_cache[1];
      41             : 
      42             :   fd_backup_overrun_t * overrun;
      43             :   fd_accdb_t *       accdb;
      44             :   fd_accdb_fork_id_t fork_id;
      45             : 
      46             :   /* compression buffer */
      47             :   ZSTD_CCtx *    zst;
      48             :   ulong          zst_in_rec; /* ZSTD_CStreamInSize() */
      49             :   uchar *        raw;
      50             :   ZSTD_inBuffer  raw_buf;
      51             :   ZSTD_outBuffer comp_buf;
      52             : 
      53             :   ulong idle_cnt;
      54             : 
      55             :   ulong kind_id;  /* index of this tile kind */
      56             :   ulong frame_id; /* sequence number for tar file names */
      57             :   ulong snapshot_slot;
      58             : 
      59             :   /* input link */
      60             :   void *  snapmk_zp_mem;
      61             :   ulong   snapmk_zp_chunk0;
      62             :   ulong   snapmk_zp_wmark;
      63             :   void *  snaprd_mem;
      64             :   ulong   snaprd_data0;
      65             :   ulong   snaprd_data1;
      66             : 
      67             :   /* snapshot files (all O_DIRECT write-only seekable) */
      68             :   int   snap_fd;      /* current snap being written */
      69             :   ulong snap_fd_cnt;  /* open snap fd count (see FD_SNAP_DIO_FD) */
      70             : 
      71             :   /* bump allocator for file offsets used to coordinate snapzp take
      72             :      turns to write to a file.  512 byte aligned for direct I/O. */
      73             :   ulong volatile * file_off;
      74             : 
      75             :   struct {
      76             :     int         active;
      77             :     fd_pubkey_t pubkey;
      78             :     fd_pubkey_t owner;
      79             :     uint        size;
      80             :     uint        acc_idx;
      81             :     ulong       data_rem;
      82             :     ulong       data_pad;
      83             :   } disk;
      84             : 
      85             :   struct {
      86             :     ulong accounts_compressed;
      87             :     ulong cache_read_torn;
      88             :     ulong bytes_compressed;
      89             :     ulong bytes_written;
      90             :     ulong io_blocked_ticks;
      91             :     ulong compress_ticks;
      92             :   } metrics;
      93             : 
      94             :   __attribute__((aligned(4096))) uchar raw_buf1 [ RAW_BUF_SZ  ];
      95             :   __attribute__((aligned(4096))) uchar comp_buf1[ COMP_BUF_SZ ];
      96             : };
      97             : typedef struct fd_snapzp fd_snapzp_t;
      98             : 
      99             : 
     100             : FD_FN_CONST static inline ulong
     101           0 : scratch_align( void ) {
     102           0 :   return FD_SHMEM_HUGE_PAGE_SZ;
     103           0 : }
     104             : 
     105             : FD_FN_PURE static inline ulong
     106           0 : scratch_footprint( fd_topo_tile_t const * tile ) {
     107           0 :   (void)tile;
     108           0 :   ulong l = FD_LAYOUT_INIT;
     109           0 :   l = FD_LAYOUT_APPEND( l, alignof(fd_snapzp_t), sizeof(fd_snapzp_t) );
     110           0 :   l = FD_LAYOUT_APPEND( l, fd_accdb_align(),     fd_accdb_footprint( tile->snapzp.max_live_slots ) );
     111           0 :   l = FD_LAYOUT_APPEND( l, 32UL,                 ZSTD_estimateCStreamSize( FD_ZSTD_LEVEL ) );
     112           0 :   return FD_LAYOUT_FINI( l, FD_SHMEM_HUGE_PAGE_SZ );
     113           0 : }
     114             : 
     115             : static void
     116             : privileged_init( fd_topo_t const *      topo,
     117           0 :                  fd_topo_tile_t const * tile ) {
     118           0 :   (void)topo;
     119           0 :   ulong snap_fd_max = tile->snapzp.snap_fd_cnt;
     120           0 :   FD_CHECK_ERR( snap_fd_max>0UL && snap_fd_max<=FD_SNAP_MAX,
     121           0 :                 "invalid snap_fd_max" );
     122           0 :   for( uint i=0U; i<snap_fd_max; i++ ) {
     123           0 :     if( FD_UNLIKELY( -1==fcntl( FD_SNAP_DIO_FD( i ), F_GETFD ) ) )
     124           0 :       FD_LOG_ERR(( "fcntl(snapshot pool fd %d) failed (%i-%s), was the snapshot pool initialized on boot?",
     125           0 :                    FD_SNAP_DIO_FD( i ), errno, fd_io_strerror( errno ) ));
     126           0 :   }
     127           0 : }
     128             : 
     129             : static void
     130             : unprivileged_init( fd_topo_t const *      topo,
     131           0 :                    fd_topo_tile_t const * tile ) {
     132           0 :   FD_CHECK_ERR( tile->kind_id < SNAPZP_TILE_MAX, "too many snapzp tiles" );
     133             : 
     134           0 :   FD_SCRATCH_ALLOC_INIT( l, fd_topo_obj_laddr( topo, tile->tile_obj_id ) );
     135           0 :   fd_snapzp_t * ctx      = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_snapzp_t), sizeof(fd_snapzp_t) );
     136           0 :   void *        _accdb   = FD_SCRATCH_ALLOC_APPEND( l, fd_accdb_align(),     fd_accdb_footprint( tile->snapzp.max_live_slots ) );
     137           0 :   void *        _zstd    = FD_SCRATCH_ALLOC_APPEND( l, 32UL,                 ZSTD_estimateCStreamSize( FD_ZSTD_LEVEL ) );
     138           0 :   FD_SCRATCH_ALLOC_FINI( l, scratch_align() );
     139             : 
     140           0 :   memset( ctx, 0, sizeof(fd_snapzp_t) );  /* 64 MiB-ish memset */
     141           0 :   ctx->snap_fd_cnt = tile->snapzp.snap_fd_cnt;
     142           0 :   ctx->snap_fd     = -1;
     143             : 
     144           0 :   ctx->zst = ZSTD_initStaticCStream( _zstd, ZSTD_estimateCStreamSize( FD_ZSTD_LEVEL ) );
     145           0 :   FD_TEST( ctx->zst );
     146           0 :   ulong zst_err;
     147           0 :   zst_err = ZSTD_CCtx_setParameter( ctx->zst, ZSTD_c_compressionLevel, FD_ZSTD_LEVEL );
     148           0 :   if( FD_UNLIKELY( ZSTD_isError( zst_err ) ) ) {
     149           0 :     FD_LOG_ERR(( "ZSTD_CCtx_setParameter(ZSTD_c_compressionLevel) failed: %s", ZSTD_getErrorName( zst_err ) ));
     150           0 :   }
     151           0 :   zst_err = ZSTD_CCtx_setParameter( ctx->zst, ZSTD_c_stableInBuffer, 1 );
     152           0 :   if( FD_UNLIKELY( ZSTD_isError( zst_err ) ) ) {
     153           0 :     FD_LOG_ERR(( "ZSTD_CCtx_setParameter(ZSTD_c_stableInBuffer=1) failed: %s", ZSTD_getErrorName( zst_err ) ));
     154           0 :   }
     155           0 :   zst_err = ZSTD_CCtx_setParameter( ctx->zst, ZSTD_c_stableOutBuffer, 1 );
     156           0 :   if( FD_UNLIKELY( ZSTD_isError( zst_err ) ) ) {
     157           0 :     FD_LOG_ERR(( "ZSTD_CCtx_setParameter(ZSTD_c_stableOutBuffer=1) failed: %s", ZSTD_getErrorName( zst_err ) ));
     158           0 :   }
     159           0 :   zst_err = ZSTD_CCtx_setParameter( ctx->zst, ZSTD_c_srcSizeHint, (int)RAW_BUF_SZ );
     160           0 :   if( FD_UNLIKELY( ZSTD_isError( zst_err ) ) ) {
     161           0 :     FD_LOG_ERR(( "ZSTD_CCtx_setParameter(ZSTD_c_srcSizeHint) failed: %s", ZSTD_getErrorName( zst_err ) ));
     162           0 :   }
     163           0 :   ctx->zst_in_rec = ZSTD_CStreamInSize();
     164           0 :   ctx->raw      = ctx->raw_buf1;
     165           0 :   ctx->raw_buf  = (ZSTD_inBuffer ){ .src = ctx->raw_buf1, .size = 0UL };
     166           0 :   ctx->comp_buf = (ZSTD_outBuffer){ .dst = ctx->comp_buf1+COMP_HEAD, .size = COMP_BUF_SZ-COMP_HEAD };
     167             : 
     168           0 :   for( ulong i=0UL; i<tile->in_cnt; i++ ) {
     169           0 :     fd_topo_link_t const * link = &topo->links[ tile->in_link_id[ i ] ];
     170           0 :     if( 0==strcmp( link->name, "snapmk_zp" ) ) {
     171           0 :       ctx->snapmk_zp_mem    = topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ].wksp;
     172           0 :       ctx->snapmk_zp_chunk0 = fd_dcache_compact_chunk0( ctx->snapmk_zp_mem, link->dcache );
     173           0 :       ctx->snapmk_zp_wmark  = fd_dcache_compact_wmark ( ctx->snapmk_zp_mem, link->dcache, link->mtu );
     174           0 :     }
     175           0 :   }
     176           0 :   FD_TEST( ctx->snapmk_zp_mem );
     177             : 
     178             :   /* discover snaprd_out link */
     179           0 :   ulong snaprd_wksp_id = fd_topo_find_wksp( topo, "snaprd_out" );
     180           0 :   FD_CHECK_ERR( snaprd_wksp_id!=ULONG_MAX, "snapzp tile not joined to snaprd_out wksp" );
     181           0 :   ulong snaprd_link_id = fd_topo_find_link( topo, "snaprd_out", 0UL );
     182           0 :   FD_CHECK_ERR( snaprd_link_id!=ULONG_MAX, "snaprd_out:0: link not found" );
     183           0 :   ulong snaprd_dcache_id = topo->links[ snaprd_link_id ].dcache_obj_id;
     184           0 :   FD_CHECK_ERR( snaprd_dcache_id!=ULONG_MAX, "snaprd_out:0: dcache_obj_id not found" );
     185           0 :   FD_CHECK_ERR( topo->objs[ snaprd_dcache_id ].wksp_id==snaprd_wksp_id, "snaprd_out:0: dcache_obj_id not in snaprd_out wksp" );
     186           0 :   uchar const * dcache = topo->links[ snaprd_link_id ].dcache;
     187           0 :   FD_CHECK_ERR( dcache, "snaprd_out:0: dcache pointer is NULL" );
     188           0 :   ctx->snaprd_data0 = (ulong)dcache;
     189           0 :   ctx->snaprd_data1 = (ulong)dcache + fd_dcache_data_sz( dcache );
     190             : 
     191           0 :   ctx->snaprd_mem = topo->workspaces[ snaprd_wksp_id ].wksp;
     192           0 :   FD_TEST( ctx->snaprd_mem );
     193             : 
     194           0 :   ctx->kind_id = tile->kind_id;
     195           0 :   ctx->frame_id = 0UL;
     196           0 :   memset( &ctx->disk, 0, sizeof(ctx->disk) );
     197             : 
     198           0 :   void * _accdb_shmem = fd_topo_obj_laddr( topo, tile->snapzp.accdb_obj_id );
     199           0 :   fd_accdb_shmem_t * accdb_shmem_ro = fd_accdb_shmem_join( _accdb_shmem );
     200           0 :   FD_TEST( accdb_shmem_ro );
     201           0 :   ulong * epoch_fseq = fd_fseq_join( fd_topo_obj_laddr( topo, tile->snapzp.accdb_epoch_obj_id ) );
     202           0 :   FD_TEST( epoch_fseq );
     203           0 :   ctx->accdb = fd_accdb_join_readonly( _accdb, accdb_shmem_ro, epoch_fseq, FD_ACCDB_FD_RO );
     204           0 :   FD_TEST( ctx->accdb );
     205           0 :   FD_TEST( fd_backup_cache_join( ctx->acc_cache, accdb_shmem_ro, epoch_fseq ) );
     206           0 :   ctx->overrun = fd_backup_overrun( fd_topo_obj_laddr( topo, tile->snapzp.visited_set_obj_id ) );
     207           0 :   FD_TEST( ctx->overrun );
     208             : 
     209           0 :   ulong * zp_fseq = fd_fseq_join( fd_topo_obj_laddr( topo, tile->snapzp.zp_fseq_id ) ); FD_TEST( zp_fseq );
     210           0 :   ctx->file_off = fd_fseq_app_laddr( zp_fseq );
     211           0 : }
     212             : 
     213             : static ulong
     214             : populate_allowed_fds( fd_topo_t const *      topo,
     215             :                       fd_topo_tile_t const * tile,
     216             :                       ulong                  out_fds_cnt,
     217           0 :                       int *                  out_fds ) {
     218           0 :   (void)topo;
     219           0 :   ulong snap_fd_cnt = tile->snapzp.snap_fd_cnt;
     220           0 :   FD_CHECK_ERR( out_fds_cnt>=3UL+snap_fd_cnt, "out_fds[] too small" );
     221           0 :   ulong out_cnt = 0UL;
     222           0 :   out_fds[ out_cnt++ ] = 2; /* stderr */
     223           0 :   if( FD_LIKELY( -1!=fd_log_private_logfile_fd() ) )
     224           0 :     out_fds[ out_cnt++ ] = fd_log_private_logfile_fd(); /* logfile */
     225           0 :   out_fds[ out_cnt++ ] = FD_ACCDB_FD_RO;
     226           0 :   for( uint i=0U; i<snap_fd_cnt; i++ )
     227           0 :     out_fds[ out_cnt++ ] = FD_SNAP_DIO_FD( i );
     228           0 :   return out_cnt;
     229           0 : }
     230             : 
     231             : static ulong
     232             : populate_allowed_seccomp( fd_topo_t const *      topo,
     233             :                           fd_topo_tile_t const * tile,
     234             :                           ulong                  out_cnt,
     235           0 :                           struct sock_filter *   out ) {
     236           0 :   (void)topo;
     237           0 :   ulong snap_fd_cnt = tile->snapzp.snap_fd_cnt;
     238           0 :   populate_sock_filter_policy_fd_snapzp_tile(
     239           0 :       out_cnt, out,
     240           0 :       (uint)fd_log_private_logfile_fd(),
     241           0 :       (uint)FD_SNAP_DIO_FD( 0 ),
     242           0 :       (uint)FD_SNAP_DIO_FD( snap_fd_cnt-1U ),
     243           0 :       (uint)FD_ACCDB_FD_RO );
     244           0 :   return sock_filter_policy_fd_snapzp_tile_instr_cnt;
     245           0 : }
     246             : 
     247             : static void
     248             : before_credit( fd_snapzp_t *       ctx,
     249             :                fd_stem_context_t * stem,
     250           0 :                int *               charge_busy ) {
     251           0 :   (void)stem; (void)charge_busy;
     252           0 :   if( FD_LIKELY( ctx->snap_fd>=0 ) ) {
     253             :     /* Don't sleep while snapshot production is active
     254             :        FIXME this is quite wasteful */
     255           0 :     ctx->idle_cnt = 0UL;
     256           0 :     return;
     257           0 :   }
     258           0 :   if( FD_UNLIKELY( ctx->idle_cnt++ > 16384UL ) ) {
     259           0 :     fd_log_sleep( (long)1e6 );
     260           0 :   }
     261           0 : }
     262             : 
     263             : /* msg_start is called on all snapzp tiles before snapshot production
     264             :    starts. */
     265             : 
     266             : static void
     267             : msg_start( fd_snapzp_t *                 ctx,
     268           0 :            fd_backup_start_msg_t const * frag ) {
     269           0 :   FD_CHECK_CRIT( frag->snap_idx < ctx->snap_fd_cnt, "invalid snapshot pool slot" );
     270           0 :   ctx->snap_fd       = FD_SNAP_DIO_FD( frag->snap_idx );
     271           0 :   ctx->fork_id       = (fd_accdb_fork_id_t){ .val = frag->fork_id };
     272           0 :   ctx->snapshot_slot = frag->slot;
     273             : 
     274           0 :   ulong zst_err = ZSTD_CCtx_reset( ctx->zst, ZSTD_reset_session_only );
     275           0 :   if( FD_UNLIKELY( ZSTD_isError( zst_err ) ) ) {
     276           0 :     FD_LOG_ERR(( "ZSTD_CCtx_reset failed: %s", ZSTD_getErrorName( zst_err ) ));
     277           0 :   }
     278           0 :   ctx->frame_id      = 0UL;
     279           0 :   memset( &ctx->disk, 0, sizeof(ctx->disk) );
     280           0 :   ctx->raw_buf.pos   = 0UL;
     281           0 :   ctx->raw_buf.size  = 0UL;
     282           0 :   ctx->comp_buf.pos  = 0UL;
     283           0 :   ctx->comp_buf.size = COMP_BUF_SZ-COMP_HEAD;
     284           0 : }
     285             : 
     286             : /* zip_work does opportunistic Zstandard compression work in memory.
     287             :    This function is tuned for a good tradeoff between latency
     288             :    (contiguous busy cycles) and throughput (dispatch overhead of libzstd
     289             :    function calls). */
     290             : 
     291             : static void
     292           0 : zip_work( fd_snapzp_t * ctx ) {
     293           0 :   if( FD_LIKELY( ctx->raw_buf.size - ctx->raw_buf.pos < ctx->zst_in_rec ) ) return;
     294           0 :   ulong raw_pos = ctx->raw_buf.pos;
     295           0 :   long  t0      = fd_tickcount();
     296           0 :   ulong ret = ZSTD_compressStream2( ctx->zst, &ctx->comp_buf, &ctx->raw_buf, ZSTD_e_continue );
     297           0 :   long  t1  = fd_tickcount();
     298           0 :   if( FD_UNLIKELY( ZSTD_isError( ret ) ) ) {
     299           0 :     FD_LOG_ERR(( "ZSTD_compressStream2(ZSTD_e_continue) failed: %s", ZSTD_getErrorName( ret ) ));
     300           0 :   }
     301           0 :   ctx->metrics.bytes_compressed += ctx->raw_buf.pos - raw_pos;
     302           0 :   ctx->metrics.compress_ticks   += (ulong)( t1-t0 );
     303           0 : }
     304             : 
     305             : /* zip_flush ends the current Zstandard compression frame and does a
     306             :    blocking direct I/O write.  Both uncompressed and compressed streams
     307             :    are padded up to 512 byte alignment to meet TAR and direct I/O
     308             :    requirements respectively. */
     309             : 
     310             : static void
     311           0 : zip_flush( fd_snapzp_t * ctx ) {
     312           0 :   FD_CHECK_CRIT( !ctx->disk.active, "attempted to flush with active defrag op" );
     313             : 
     314             :   /* Align input frame by 512 bytes (TAR file format) */
     315           0 :   ulong content_usz = ctx->raw_buf.size;
     316           0 :   ulong content_asz = fd_ulong_align_up( content_usz, 512UL );
     317           0 :   if( content_asz > content_usz ) {
     318           0 :     FD_TEST( content_asz <= RAW_BUF_SZ );
     319           0 :     fd_memset( ctx->raw + content_usz, 0, content_asz - content_usz );
     320           0 :     ctx->raw_buf.size = content_asz;
     321           0 :   }
     322             : 
     323             :   /* Finish content compression frame */
     324           0 :   ulong raw_pos = ctx->raw_buf.pos;
     325           0 :   long  t0      = fd_tickcount();
     326           0 :   ulong ret = ZSTD_compressStream2( ctx->zst, &ctx->comp_buf, &ctx->raw_buf, ZSTD_e_end );
     327           0 :   long  t1  = fd_tickcount();
     328           0 :   if( FD_UNLIKELY( ZSTD_isError( ret ) ) ) {
     329           0 :     FD_LOG_ERR(( "ZSTD_compressStream2(ZSTD_e_end) failed: %s", ZSTD_getErrorName( ret ) ));
     330           0 :   }
     331           0 :   if( FD_UNLIKELY( ret!=0UL ) ) {
     332           0 :     FD_LOG_ERR(( "ZSTD_compressStream2(ZSTD_e_end) did not finish frame" ));
     333           0 :   }
     334           0 :   ctx->metrics.bytes_compressed += ctx->raw_buf.pos - raw_pos;
     335           0 :   ctx->metrics.compress_ticks   += (ulong)( t1-t0 );
     336           0 :   FD_TEST( ctx->raw_buf.pos == ctx->raw_buf.size );
     337           0 :   ctx->raw_buf.pos  = 0UL;
     338           0 :   ctx->raw_buf.size = 0UL;
     339             : 
     340             :   /* Prepend compression frame with a TAR header
     341             :      (Zstandard frame with a 512 byte uncompressed block) */
     342           0 :   uchar * comp_head = (uchar *)ctx->comp_buf.dst - COMP_HEAD;
     343           0 :   memcpy( comp_head, (uchar[]){0x28,0xB5,0x2F,0xFD,0x60,0x00,0x01,0x01,0x10,0x00}, 10 );
     344           0 :   fd_tar_meta_t meta; fd_backup_tar_file_hdr( &meta, content_usz );
     345             : 
     346             :   /* Generate a unique file name */
     347           0 :   ulong frame_id = ctx->frame_id++;
     348           0 :   ulong vec_id   = (frame_id * SNAPZP_TILE_MAX) + ctx->kind_id;
     349           0 :   do {
     350           0 :     ulong slot = ctx->snapshot_slot;
     351           0 :     char * p = fd_cstr_init( meta.name );
     352           0 :     p = fd_cstr_append_cstr( p, "accounts/" );
     353           0 :     p = fd_cstr_append_ulong_as_text( p, 0, 0, slot,   fd_ulong_base10_dig_cnt( slot   ) );
     354           0 :     p = fd_cstr_append_char( p, '.' );
     355           0 :     p = fd_cstr_append_ulong_as_text( p, 0, 0, vec_id, fd_ulong_base10_dig_cnt( vec_id ) );
     356           0 :     fd_cstr_fini( p );
     357           0 :   } while(0);
     358           0 :   fd_tar_meta_set_chksum( &meta );
     359           0 :   memcpy( comp_head+10, &meta, sizeof(fd_tar_meta_t) );
     360             : 
     361             :   /* Align to block size with a skippable frame */
     362           0 :   ulong comp_usz = COMP_HEAD + ctx->comp_buf.pos;
     363           0 :   ulong comp_asz = fd_ulong_align_up( comp_usz, 4096UL );
     364           0 :   ulong pad_sz   = comp_asz - comp_usz;
     365           0 :   if( FD_UNLIKELY( pad_sz>0UL && pad_sz<8UL ) ) {
     366           0 :     comp_asz += 4096UL;
     367           0 :     pad_sz   += 4096UL;
     368           0 :   }
     369           0 :   FD_TEST( comp_asz <= COMP_BUF_SZ );
     370           0 :   if( FD_LIKELY( pad_sz>0UL ) ) {
     371           0 :     uchar * tail = (uchar *)ctx->comp_buf.dst + ctx->comp_buf.pos;
     372           0 :     FD_STORE( uint, tail,   ZSTD_MAGIC_SKIPPABLE_START );
     373           0 :     FD_STORE( uint, tail+4, (uint)( pad_sz-8 ) );
     374           0 :     fd_memset( tail+8, 0, pad_sz-8 );
     375           0 :   }
     376             : 
     377             :   /* Allocate file range to write into */
     378           0 :   ulong off = __atomic_fetch_add( ctx->file_off, comp_asz, __ATOMIC_RELAXED );
     379           0 :   FD_TEST( fd_ulong_is_aligned( off,      4096UL ) );
     380           0 :   FD_TEST( fd_ulong_is_aligned( comp_asz, 4096UL ) );
     381           0 :   t0 = fd_tickcount();
     382           0 :   long write_sz = pwrite( ctx->snap_fd, comp_head, comp_asz, (long)off );
     383           0 :   t1 = fd_tickcount();
     384           0 :   if( FD_UNLIKELY( write_sz!=(long)comp_asz ) ) {
     385           0 :     FD_LOG_ERR(( "pwrite failed: %i-%s", errno, fd_io_strerror( errno ) ));
     386           0 :   }
     387           0 :   ctx->metrics.bytes_written    += comp_asz;
     388           0 :   ctx->metrics.io_blocked_ticks += (ulong)( t1-t0 );
     389             : 
     390             :   /* Free compressed buffer */
     391           0 :   ctx->comp_buf.pos = 0UL;
     392           0 : }
     393             : 
     394             : /* accmeta_await_evict waits until the account data belonging to the
     395             :    given index entry is evicted from cache to disk.  This is used to
     396             :    fallback to disk reads when a cache read is torn by eviction. */
     397             : 
     398             : static void
     399             : accmeta_await_evict( fd_snapzp_t * ctx,
     400           0 :                      uint          acc_idx ) {
     401           0 :   fd_backup_accidx_t * idx = &ctx->acc_cache->idx;
     402           0 :   FD_CHECK_CRIT( fd_backup_accidx_valid( idx, acc_idx ), "invalid account index" );
     403             : 
     404           0 :   fd_accdb_accmeta_t const * acc = &idx->acc_pool[ acc_idx ];
     405           0 :   for(;;) {
     406           0 :     FD_COMPILER_MFENCE();
     407           0 :     FD_VOLATILE( *idx->epoch_slot ) = FD_VOLATILE_CONST( *idx->epoch );
     408           0 :     FD_HW_MFENCE();
     409             : 
     410           0 :     ulong off_packed = FD_VOLATILE_CONST( acc->offset_fork );
     411           0 :     int   done       = ( off_packed & FD_ACCDB_OFF_MASK )!=FD_ACCDB_OFF_INVAL;
     412             : 
     413           0 :     FD_COMPILER_MFENCE();
     414           0 :     FD_VOLATILE( *idx->epoch_slot ) = ULONG_MAX;
     415             : 
     416           0 :     if( FD_LIKELY( done ) ) break;
     417           0 :     FD_SPIN_PAUSE(); /* FIXME yield to OS instead? */
     418           0 :   }
     419             : 
     420             :   /* tell snapmk that we were overrun */
     421           0 :   fd_backup_overrun_push( ctx->overrun, acc_idx );
     422           0 :   ctx->metrics.cache_read_torn++;
     423             : 
     424           0 :   FD_COMPILER_MFENCE();
     425           0 : }
     426             : 
     427             : /* msg_acc_cache instructs snapzp to gather, compress, and write out a
     428             :    bunch of accounts in cache.  Note that accdb cache entries are not
     429             :    pinned.  Account cache data can be evicted during read, leading to
     430             :    use-after-free, which this function gracefully recovers from. */
     431             : 
     432             : static void
     433             : msg_acc_cache( fd_snapzp_t *                 ctx,
     434           0 :                fd_backup_cache_msg_t const * batch ) {
     435           0 :   FD_CHECK_CRIT( ctx->snap_fd>=0, "invalid snapshot file descriptor" );
     436             : 
     437           0 :   fd_backup_accidx_t * idx      = &ctx->acc_cache->idx;
     438           0 :   int                  in_epoch = 0;
     439             : 
     440           0 :   ZSTD_inBuffer * buf = &ctx->raw_buf;
     441           0 :   for( ulong i=0UL; i<FD_BACKUP_CACHE_PARA; i++ ) {
     442           0 :     fd_pubkey_t const * pubkey  = &batch->pubkey [ i ];
     443           0 :     uint                acc_idx =  batch->acc_idx[ i ];
     444           0 :     if( acc_idx==UINT_MAX ) continue;
     445             : 
     446           0 :     if( FD_UNLIKELY( !in_epoch ) ) {
     447           0 :       FD_COMPILER_MFENCE();
     448           0 :       FD_VOLATILE( *idx->epoch_slot ) = FD_VOLATILE_CONST( *idx->epoch );
     449             :       /* a lock prefix is an expensive CPU pipeline hazard, therefore
     450             :          we hold onto our epoch for multiple accounts */
     451           0 :       FD_HW_MFENCE();
     452           0 :       in_epoch = 1;
     453           0 :     }
     454             : 
     455           0 :     int err = fd_backup_cache_read( ctx->acc_cache, pubkey, acc_idx, ctx->raw, &buf->size, RAW_BUF_SZ );
     456           0 :     if( FD_UNLIKELY( err==FD_BACKUP_CACHE_ERR_SPACE ) ) {
     457           0 :       FD_COMPILER_MFENCE();
     458           0 :       FD_VOLATILE( *idx->epoch_slot ) = ULONG_MAX;
     459           0 :       zip_flush( ctx );
     460           0 :       FD_COMPILER_MFENCE();
     461           0 :       FD_VOLATILE( *idx->epoch_slot ) = FD_VOLATILE_CONST( *idx->epoch );
     462           0 :       FD_HW_MFENCE();
     463           0 :       err = fd_backup_cache_read( ctx->acc_cache, pubkey, acc_idx, ctx->raw, &buf->size, RAW_BUF_SZ );
     464           0 :       FD_CHECK_ERR( err!=FD_BACKUP_CACHE_ERR_SPACE, "Zstandard buffer too small" );
     465           0 :     }
     466             : 
     467           0 :     if( FD_UNLIKELY( err==FD_BACKUP_CACHE_ERR_MISS ) ) {
     468           0 :       FD_COMPILER_MFENCE();
     469           0 :       FD_VOLATILE( *idx->epoch_slot ) = ULONG_MAX;
     470           0 :       in_epoch = 0;
     471           0 :       accmeta_await_evict( ctx, acc_idx );
     472           0 :       continue;
     473           0 :     }
     474           0 :     FD_CHECK_ERR( err==FD_BACKUP_CACHE_SUCCESS, "unexpected cache error code" );
     475           0 :     ctx->metrics.accounts_compressed++;
     476           0 :   }
     477             : 
     478           0 :   if( FD_LIKELY( in_epoch ) ) {
     479           0 :     FD_COMPILER_MFENCE();
     480           0 :     FD_VOLATILE( *idx->epoch_slot ) = ULONG_MAX;
     481           0 :   }
     482           0 : }
     483             : 
     484             : static void
     485             : msg_acc_delta( fd_snapzp_t *                 ctx,
     486           0 :                fd_backup_delta_msg_t const * batch ) {
     487           0 :   FD_CHECK_CRIT( ctx->snap_fd>=0, "invalid snapshot file descriptor" );
     488           0 :   FD_CHECK_CRIT( !ctx->disk.active, "received account delta while already processing a disk account" );
     489           0 :   FD_CHECK_CRIT( batch->cnt<=FD_BACKUP_CACHE_PARA, "invalid delta account batch" );
     490             : 
     491           0 :   ulong const rec_max = sizeof(snap_acc_hdr_t) + FD_RUNTIME_ACC_SZ_MAX;
     492           0 :   FD_STATIC_ASSERT( sizeof(snap_acc_hdr_t)+FD_RUNTIME_ACC_SZ_MAX<=RAW_BUF_SZ, raw_buf_too_small );
     493             : 
     494           0 :   for( ulong i=0UL; i<(ulong)batch->cnt; i++ ) {
     495           0 :     if( FD_UNLIKELY( ctx->raw_buf.size + rec_max > RAW_BUF_SZ ) ) zip_flush( ctx );
     496             : 
     497           0 :     ulong            start = ctx->raw_buf.size;
     498           0 :     snap_acc_hdr_t * hdr   = (snap_acc_hdr_t *)( ctx->raw + start );
     499           0 :     memset( hdr, 0, sizeof(snap_acc_hdr_t) );
     500           0 :     hdr->pubkey = batch->pubkey[ i ];
     501             : 
     502           0 :     ulong lamports   = 0UL;
     503           0 :     ulong data_len   = 0UL;
     504           0 :     int   executable = 0;
     505           0 :     fd_accdb_read_one_nocache( ctx->accdb, ctx->fork_id, batch->pubkey[ i ].uc,
     506           0 :                                &lamports, &executable, hdr->owner.uc,
     507           0 :                                ctx->raw + start + sizeof(snap_acc_hdr_t), &data_len );
     508           0 :     FD_CHECK_CRIT( data_len<=FD_RUNTIME_ACC_SZ_MAX, "accdb returned oversized account" );
     509           0 :     hdr->lamports   = lamports;
     510           0 :     hdr->executable = (uchar)!!executable;
     511           0 :     hdr->data_len   = data_len;
     512             : 
     513           0 :     ulong data_pad = fd_ulong_align_up( data_len, 8UL ) - data_len;
     514           0 :     if( data_pad ) fd_memset( ctx->raw + start + sizeof(snap_acc_hdr_t) + data_len, 0, data_pad );
     515           0 :     ctx->raw_buf.size = start + sizeof(snap_acc_hdr_t) + data_len + data_pad;
     516           0 :     ctx->metrics.accounts_compressed++;
     517           0 :   }
     518           0 : }
     519             : 
     520             : /* accmeta_disk validates that an index entry (at acc_idx with given
     521             :    pubkey) is an on-disk rooted account.
     522             :    (Safe while compaction and rooting are disabled, as on-disk rooted
     523             :    accounts are pinned in the index and on-disk under these conditions.
     524             : 
     525             :    Returns a pointer to the index entry if a matching record is found,
     526             :    NULL otherwise.  (Never returns NULL under correct usage.) */
     527             : 
     528             : static fd_accdb_accmeta_t const *
     529             : accmeta_disk( fd_snapzp_t *       ctx,
     530             :               fd_pubkey_t const * pubkey,
     531             :               uint                size,
     532           0 :               uint                acc_idx ) {
     533           0 :   fd_backup_accidx_t const * idx = &ctx->acc_cache->idx;
     534           0 :   if( FD_UNLIKELY( !fd_backup_accidx_valid( idx, acc_idx ) ) ) return NULL;
     535             : 
     536           0 :   fd_accdb_accmeta_t const * acc = &idx->acc_pool[ acc_idx ];
     537           0 :   uint es = FD_VOLATILE_CONST( acc->executable_size );
     538           0 :   if( FD_UNLIKELY( FD_ACCDB_SIZE_DATA( es )!=FD_ACCDB_SIZE_DATA( size ) ) ) return NULL;
     539           0 :   if( FD_UNLIKELY( memcmp( acc->key.pubkey, pubkey->uc, sizeof(fd_pubkey_t) ) ) ) return NULL;
     540           0 :   return acc;
     541           0 : }
     542             : 
     543             : /* msg_acc_disk instructs snapzp to compress an account fragment that
     544             :    was read from the accdb disk file.  (slow path)
     545             : 
     546             :    The first fragment of an account has an associated backup_disk_msg
     547             :    descriptor (chunk serves as ptr, sz is the descriptor sz, i.e.
     548             :    sizeof(fd_backup_disk_msg_t)).  The first frag is indicated by the
     549             :    ctl.som flag.
     550             : 
     551             :    The remaining fragments do not have a descriptor.  The last frag is
     552             :    indicated by the ctl.eom frag.
     553             : 
     554             :    The account data fragment size is in tspub.
     555             : 
     556             :    msg_acc_disk_start is a helper function that starts a disk account
     557             :    defrag operation.  Returns the number of bytes consumed (always the
     558             :    frag data size). */
     559             : 
     560             : static ulong
     561             : msg_acc_disk_start( fd_snapzp_t *                ctx,
     562           0 :                     fd_backup_disk_msg_t const * frag ) {
     563           0 :   FD_CHECK_CRIT( ctx->snap_fd>=0, "invalid snapshot file descriptor" );
     564           0 :   FD_CHECK_CRIT( !ctx->disk.active, "received account SOM while already processing a disk account" );
     565             : 
     566           0 :   ulong data_len = (ulong)FD_ACCDB_SIZE_DATA( frag->size );
     567           0 :   ulong rec_sz   = sizeof(snap_acc_hdr_t) + fd_ulong_align_up( data_len, 8UL );
     568           0 :   FD_CHECK_CRIT( rec_sz<=RAW_BUF_SZ, "oversize snapshot account record" );
     569           0 :   FD_CHECK_CRIT( frag->snap_sz==rec_sz, "disk account snapshot size mismatch" );
     570           0 :   if( FD_UNLIKELY( ctx->raw_buf.size + rec_sz > RAW_BUF_SZ ) ) {
     571           0 :     zip_flush( ctx );
     572           0 :   }
     573             : 
     574           0 :   memset( &ctx->disk, 0, sizeof(ctx->disk) );
     575           0 :   ctx->disk.active  = 1;
     576           0 :   ctx->disk.pubkey  = frag->pubkey;
     577           0 :   ctx->disk.owner   = frag->owner;
     578           0 :   ctx->disk.size    = frag->size;
     579           0 :   ctx->disk.acc_idx = frag->acc_idx;
     580             : 
     581           0 :   fd_accdb_accmeta_t const * accmeta = accmeta_disk( ctx, &ctx->disk.pubkey, ctx->disk.size, ctx->disk.acc_idx );
     582           0 :   FD_CHECK_CRIT( accmeta, "bug in snapshot producer: rooted account disappeared from index" );
     583             : 
     584           0 :   snap_acc_hdr_t * hdr = (snap_acc_hdr_t *)( ctx->raw + ctx->raw_buf.size );
     585           0 :   memset( hdr, 0, sizeof(snap_acc_hdr_t) );
     586           0 :   hdr->pubkey    = ctx->disk.pubkey;
     587           0 :   hdr->owner     = ctx->disk.owner;
     588           0 :   hdr->lamports   = FD_VOLATILE_CONST( accmeta->lamports );
     589           0 :   hdr->executable = !!FD_ACCDB_SIZE_EXEC( FD_VOLATILE_CONST( accmeta->executable_size ) );
     590           0 :   hdr->data_len   = data_len;
     591             : 
     592           0 :   ctx->raw_buf.size += sizeof(snap_acc_hdr_t);
     593           0 :   ctx->disk.data_rem = data_len;
     594           0 :   ctx->disk.data_pad = fd_ulong_align_up( data_len, 8UL ) - data_len;
     595           0 :   return (ulong)frag->data_sz;
     596           0 : }
     597             : 
     598             : static void
     599             : msg_acc_disk( fd_snapzp_t * ctx,
     600             :               ulong         seq,       /* unused */
     601             :               ulong         sig,       /* data pointer */
     602             :               ulong         chunk,     /* descriptor pointer */
     603             :               ulong         sz,        /* descriptor size */
     604             :               ulong         ctl,       /* holds orig, som, eom */
     605             :               ulong         tsorig,    /* unused */
     606           0 :               ulong         tspub ) {  /* data size */
     607           0 :   (void)seq; (void)tsorig;
     608           0 :   int som = fd_frag_meta_ctl_som( ctl );
     609           0 :   int eom = fd_frag_meta_ctl_eom( ctl );
     610             : 
     611             :   /* begin defrag operation */
     612           0 :   ulong frag_sz = tspub;
     613           0 :   if( FD_UNLIKELY( som ) ) {
     614           0 :     FD_CHECK_CRIT( chunk>=ctx->snapmk_zp_chunk0 && chunk<=ctx->snapmk_zp_wmark && sz==sizeof(fd_backup_disk_msg_t),
     615           0 :                    "input frag bounds check failed: fd_backup_disk_msg_t(som=1)" );
     616           0 :     fd_backup_disk_msg_t const * frag = fd_chunk_to_laddr_const( ctx->snapmk_zp_mem, chunk );
     617           0 :     frag_sz = msg_acc_disk_start( ctx, frag );
     618           0 :     if( FD_UNLIKELY( tspub!=frag_sz ) ) {
     619           0 :       FD_LOG_CRIT(( "invalid accdb disk frag stream: size mismatch (%lu != %lu)", tspub, frag_sz ));
     620           0 :     }
     621           0 :   } else {
     622           0 :     FD_CHECK_CRIT( !sz, "invalid accdb disk frag stream: non-SOM frag must not have a descriptor" );
     623           0 :   }
     624           0 :   FD_CHECK_CRIT( !!ctx->disk.active, "invalid accdb disk frag stream: non-SOM frag seen but no active defrag op" );
     625             : 
     626             :   /* locate data pointer */
     627           0 :   uchar const * frag = NULL;
     628           0 :   if( FD_LIKELY( ctx->disk.data_rem ) ) {
     629           0 :     frag = fd_wksp_laddr_fast( ctx->snaprd_mem, sig );
     630           0 :   }
     631             : 
     632             :   /* defrag copy */
     633           0 :   ulong take = fd_ulong_min( ctx->disk.data_rem, frag_sz );
     634           0 :   if( FD_LIKELY( take ) ) {
     635           0 :     FD_CHECK_CRIT( ctx->raw_buf.size + take <= RAW_BUF_SZ,
     636           0 :                    "internal bounds check failed" );
     637           0 :     FD_CHECK_CRIT( (ulong)frag           >= ctx->snaprd_data0 &&
     638           0 :                    (ulong)frag + frag_sz <= ctx->snaprd_data1,
     639           0 :                    "snaprd bounds check failed" );
     640           0 :     fd_memcpy( ctx->raw + ctx->raw_buf.size, frag, take );
     641           0 :     ctx->raw_buf.size  += take;
     642           0 :     ctx->disk.data_rem -= take;
     643           0 :     frag_sz            -= take;
     644           0 :   }
     645           0 :   FD_CHECK_CRIT( !frag_sz, "invalid accdb disk frag stream: frag spans multiple accounts" );
     646           0 :   FD_CHECK_CRIT( !( !ctx->disk.data_rem && !eom ), "invalid accdb disk frag stream: non-EOM frag seen but data already complete" );
     647             : 
     648             :   /* finish defrag operation */
     649           0 :   if( eom ) {
     650           0 :     FD_CHECK_CRIT( !ctx->disk.data_rem, "invalid accdb disk frag stream: EOM frag seen but defrag not complete" );
     651           0 :     if( ctx->disk.data_pad ) {
     652           0 :       FD_TEST( ctx->raw_buf.size + ctx->disk.data_pad <= RAW_BUF_SZ );
     653           0 :       fd_memset( ctx->raw + ctx->raw_buf.size, 0, ctx->disk.data_pad );
     654           0 :       ctx->raw_buf.size += ctx->disk.data_pad;
     655           0 :     }
     656           0 :     ctx->metrics.accounts_compressed++;
     657           0 :     memset( &ctx->disk, 0, sizeof(ctx->disk) );
     658           0 :   }
     659           0 : }
     660             : 
     661             : /* msg_acc_disk instructions snapzp to compress a batch of unfragmented
     662             :    accounts that were read from the accdb disk file.  (fast path)  */
     663             : 
     664             : static void
     665             : msg_acc_disk_batch( fd_snapzp_t *                      ctx,
     666             :                     fd_backup_disk_batch_msg_t const * batch,
     667           0 :                     ulong                              sig ) {
     668           0 :   FD_CHECK_CRIT( ctx->snap_fd>=0, "invalid snapshot file descriptor" );
     669           0 :   FD_CHECK_CRIT( !ctx->disk.active, "received account batch while already processing a disk account" );
     670             : 
     671           0 :   fd_backup_accidx_t const * idx      = &ctx->acc_cache->idx;
     672           0 :   fd_accdb_accmeta_t const * acc_pool = idx->acc_pool;
     673             : 
     674             :   /* MLP gather of account index entries */
     675           0 :   static fd_accdb_accmeta_t const dead = {0};
     676           0 :   fd_accdb_accmeta_t const * gather[ FD_BACKUP_DISK_PARA ];
     677           0 :   for( ulong i=0UL; i<FD_BACKUP_DISK_PARA; i++ ) {
     678           0 :     uint ai = batch->acc_idx[ i ];
     679           0 :     gather[ i ] = fd_backup_accidx_valid( idx, ai ) ? &acc_pool[ ai ] : &dead;
     680           0 :   }
     681           0 :   ulong lamports[ FD_BACKUP_DISK_PARA ];
     682           0 :   uint  exec_sz [ FD_BACKUP_DISK_PARA ];
     683           0 :   for( ulong i=0UL; i<FD_BACKUP_DISK_PARA; i++ ) {
     684           0 :     lamports[ i ] = FD_VOLATILE_CONST( gather[ i ]->lamports        );
     685           0 :     exec_sz [ i ] = FD_VOLATILE_CONST( gather[ i ]->executable_size );
     686           0 :   }
     687             : 
     688             :   /* Bounds check batch (TOCTOU susceptible, but this is an accepted
     689             :      risk, as snapmk->snapzp is a trusted link) */
     690           0 :   uchar const * base = fd_wksp_laddr_fast( ctx->snaprd_mem, sig );
     691           0 :   for( ulong i=0UL; i<FD_BACKUP_DISK_PARA; i++ ) {
     692           0 :     FD_CHECK_CRIT( ((ulong)base + batch->frag_off[ i ] >= ctx->snaprd_data0) &
     693           0 :                    ((ulong)base + batch->frag_off[ i ] + sizeof(fd_accdb_disk_meta_t) <= (ulong)ctx->snaprd_data1),
     694           0 :                    "account data bounds check fail" );
     695           0 :   }
     696             : 
     697             :   /* Sequential scan of disk data in frag */
     698           0 :   for( ulong i=0UL; i<FD_BACKUP_DISK_PARA; i++ ) {
     699           0 :     uint acc_idx = batch->acc_idx[ i ];
     700           0 :     if( acc_idx==UINT_MAX ) continue;
     701           0 :     FD_CHECK_CRIT( fd_backup_accidx_valid( idx, acc_idx ), "account index bounds check fail" );
     702             : 
     703           0 :     fd_accdb_disk_meta_t const * dm = (fd_accdb_disk_meta_t const *)( base + batch->frag_off[ i ] );
     704           0 :     FD_CHECK_CRIT( (ulong)(dm+1) <= (ulong)ctx->snaprd_data1, "account data bounds check fail" );
     705             : 
     706           0 :     ulong data_len = (ulong)FD_ACCDB_SIZE_DATA( dm->size );
     707           0 :     FD_CHECK_CRIT( (ulong)(dm+1)+data_len <= (ulong)ctx->snaprd_data1, "account data bounds check fail" );
     708             : 
     709             :     /* validate that disk data matches index */
     710           0 :     FD_CHECK_CRIT( FD_ACCDB_SIZE_DATA( exec_sz[ i ] )==data_len, "account query corruption detected" );
     711           0 :     FD_CHECK_CRIT( !memcmp( gather[ i ]->key.pubkey, dm->pubkey, sizeof(fd_pubkey_t) ), "account query corruption detected" );
     712             : 
     713           0 :     ulong rec_sz   = sizeof(snap_acc_hdr_t) + fd_ulong_align_up( data_len, 8UL );
     714           0 :     ulong data_pad = fd_ulong_align_up( data_len, 8UL ) - data_len;
     715           0 :     FD_CHECK_CRIT( rec_sz<=RAW_BUF_SZ, "oversize snapshot account record" );
     716           0 :     if( FD_UNLIKELY( ctx->raw_buf.size + rec_sz > RAW_BUF_SZ ) ) {
     717           0 :       zip_flush( ctx );
     718           0 :     }
     719             : 
     720           0 :     snap_acc_hdr_t * hdr = (snap_acc_hdr_t *)( ctx->raw + ctx->raw_buf.size );
     721           0 :     memset( hdr, 0, sizeof(snap_acc_hdr_t) );
     722           0 :     memcpy( hdr->pubkey.uc, dm->pubkey, sizeof(fd_pubkey_t) );
     723           0 :     memcpy( hdr->owner.uc,  dm->owner,  sizeof(fd_pubkey_t) );
     724           0 :     hdr->lamports   = lamports[ i ];
     725           0 :     hdr->executable = !!FD_ACCDB_SIZE_EXEC( exec_sz[ i ] );
     726           0 :     hdr->data_len   = data_len;
     727           0 :     ctx->raw_buf.size += sizeof(snap_acc_hdr_t);
     728             : 
     729           0 :     if( FD_LIKELY( data_len ) ) {
     730           0 :       uchar const * data = base + batch->frag_off[ i ] + sizeof(fd_accdb_disk_meta_t);
     731           0 :       fd_memcpy( ctx->raw + ctx->raw_buf.size, data, data_len );
     732           0 :       ctx->raw_buf.size += data_len;
     733           0 :     }
     734           0 :     if( data_pad ) {
     735           0 :       fd_memset( ctx->raw + ctx->raw_buf.size, 0, data_pad );
     736           0 :       ctx->raw_buf.size += data_pad;
     737           0 :     }
     738           0 :     ctx->metrics.accounts_compressed++;
     739           0 :   }
     740           0 : }
     741             : 
     742             : /* msg_done is called on all snapzp tiles once all account data has been
     743             :    compressed.  This causes snapzp to enter sleep state. */
     744             : 
     745             : static void
     746           0 : msg_done( fd_snapzp_t * ctx ) {
     747             :   /* Leave file descriptors open, but release local reference */
     748           0 :   ctx->snap_fd = -1;
     749           0 : }
     750             : 
     751             : /* returnable_frag is called for every message received from snapmk. */
     752             : 
     753             : static int
     754             : returnable_frag( fd_snapzp_t *       ctx,
     755             :                  ulong               in_idx,
     756             :                  ulong               seq,
     757             :                  ulong               sig,
     758             :                  ulong               chunk,
     759             :                  ulong               sz,
     760             :                  ulong               ctl,
     761             :                  ulong               tsorig,
     762             :                  ulong               tspub,
     763           0 :                  fd_stem_context_t * stem ) {
     764           0 :   (void)in_idx; (void)stem;
     765           0 :   ctx->idle_cnt = 0UL;
     766           0 :   ulong orig = fd_frag_meta_ctl_orig( ctl );
     767             : 
     768           0 : # define MSG_TRANSLATE( msg_type ) __extension__({ \
     769           0 :     FD_CHECK_CRIT( chunk >= ctx->snapmk_zp_chunk0 && chunk <= ctx->snapmk_zp_wmark && sz==sizeof(msg_type), "input frag bounds check failed: " #msg_type ); \
     770           0 :     (msg_type const *)fd_chunk_to_laddr_const( ctx->snapmk_zp_mem, chunk ); \
     771           0 :   })
     772             : 
     773           0 :   switch( orig ) {
     774           0 :   case FD_BACKUP_ORIG_START:
     775           0 :     msg_start( ctx, MSG_TRANSLATE( fd_backup_start_msg_t ) );
     776           0 :     break;
     777           0 :   case FD_BACKUP_ORIG_ACC_CACHE:
     778           0 :     msg_acc_cache( ctx, MSG_TRANSLATE( fd_backup_cache_msg_t ) );
     779           0 :     zip_work( ctx );
     780           0 :     break;
     781           0 :   case FD_BACKUP_ORIG_ACC_DELTA:
     782           0 :     msg_acc_delta( ctx, MSG_TRANSLATE( fd_backup_delta_msg_t ) );
     783           0 :     zip_work( ctx );
     784           0 :     break;
     785           0 :   case FD_BACKUP_ORIG_ACC_DISK:
     786           0 :     msg_acc_disk( ctx, seq, sig, chunk, sz, ctl, tsorig, tspub );
     787           0 :     zip_work( ctx );
     788           0 :     break;
     789           0 :   case FD_BACKUP_ORIG_ACC_DISK_BATCH:
     790           0 :     msg_acc_disk_batch( ctx, MSG_TRANSLATE( fd_backup_disk_batch_msg_t ), sig );
     791           0 :     zip_work( ctx );
     792           0 :     break;
     793           0 :   case FD_BACKUP_ORIG_FLUSH:
     794           0 :     zip_flush( ctx );
     795           0 :     break;
     796           0 :   case FD_BACKUP_ORIG_DONE:
     797           0 :     msg_done( ctx );
     798           0 :     break;
     799           0 :   default:
     800           0 :     FD_LOG_CRIT(( "unknown backup instruction (orig=%lu, seq=%lu)", orig, seq ));
     801           0 :   }
     802             : 
     803           0 :   return 0;
     804           0 : }
     805             : 
     806             : static void
     807           0 : metrics_write( fd_snapzp_t * ctx ) {
     808           0 :   FD_MCNT_SET( SNAPZP, ACCOUNTS_COMPRESSED,         ctx->metrics.accounts_compressed );
     809           0 :   FD_MCNT_SET( SNAPZP, BYTES_COMPRESSED,            ctx->metrics.bytes_compressed    );
     810           0 :   FD_MCNT_SET( SNAPZP, BYTES_WRITTEN,               ctx->metrics.bytes_written       );
     811           0 :   FD_MCNT_SET( SNAPZP, IO_BLOCKED_DURATION_SECONDS, ctx->metrics.io_blocked_ticks    );
     812           0 :   FD_MCNT_SET( SNAPZP, COMPRESS_DURATION_SECONDS,   ctx->metrics.compress_ticks      );
     813           0 :   FD_MCNT_SET( SNAPZP, CACHE_READ_TORN,             ctx->metrics.cache_read_torn     );
     814           0 : }
     815             : 
     816           0 : #define STEM_BURST 1UL
     817           0 : #define STEM_LAZY  9400UL
     818           0 : #define STEM_CALLBACK_CONTEXT_TYPE    fd_snapzp_t
     819           0 : #define STEM_CALLBACK_CONTEXT_ALIGN   alignof(fd_snapzp_t)
     820           0 : #define STEM_CALLBACK_BEFORE_CREDIT   before_credit
     821           0 : #define STEM_CALLBACK_RETURNABLE_FRAG returnable_frag
     822           0 : #define STEM_CALLBACK_METRICS_WRITE   metrics_write
     823             : #include "../../disco/stem/fd_stem.c"
     824             : 
     825             : #ifndef FD_TILE_TEST
     826             : fd_topo_run_tile_t fd_tile_snapzp = {
     827             :   .name                     = "snapzp",
     828             :   .populate_allowed_fds     = populate_allowed_fds,
     829             :   .populate_allowed_seccomp = populate_allowed_seccomp,
     830             :   .scratch_align            = scratch_align,
     831             :   .scratch_footprint        = scratch_footprint,
     832             :   .privileged_init          = privileged_init,
     833             :   .unprivileged_init        = unprivileged_init,
     834             :   .run                      = stem_run,
     835             : };
     836             : #endif

Generated by: LCOV version 1.14