LCOV - code coverage report
Current view: top level - flamenco/snapshot - fd_snapshot_main.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 260 0.0 %
Date: 2025-03-20 12:08:36 Functions: 0 9 0.0 %

          Line data    Source code
       1             : #include "fd_snapshot_loader.h"
       2             : #include "fd_snapshot_http.h"
       3             : #include "fd_snapshot_restore_private.h"
       4             : #include "../runtime/fd_acc_mgr.h"
       5             : #include "../runtime/context/fd_exec_epoch_ctx.h"
       6             : #include "../runtime/context/fd_exec_slot_ctx.h"
       7             : #include "../../ballet/zstd/fd_zstd.h"
       8             : #include "../../flamenco/types/fd_types.h"
       9             : #include "../../flamenco/types/fd_types_yaml.h"
      10             : 
      11             : #include <assert.h>
      12             : #include <errno.h>
      13             : #include <fcntl.h>
      14             : #include <netdb.h>
      15             : #include <regex.h>
      16             : #include <stddef.h>
      17             : #include <stdio.h>
      18             : #include <stdlib.h>
      19             : #include <unistd.h>
      20             : #include <sys/random.h>
      21             : 
      22             : /* Snapshot restore ***************************************************/
      23             : 
      24           0 : #define OSTREAM_BUFSZ (32768UL)
      25             : 
      26             : struct fd_snapshot_dumper {
      27             :   fd_alloc_t *   alloc;
      28             :   fd_funk_t *    funk;
      29             :   fd_acc_mgr_t * acc_mgr;
      30             : 
      31             :   fd_exec_epoch_ctx_t * epoch_ctx;
      32             :   fd_exec_slot_ctx_t *  slot_ctx;
      33             : 
      34             :   int snapshot_fd;
      35             : 
      36             :   fd_snapshot_loader_t *  loader;
      37             :   fd_snapshot_restore_t * restore;
      38             : 
      39             :   int                      yaml_fd;
      40             : 
      41             :   int                      csv_fd;
      42             :   fd_io_buffered_ostream_t csv_out;
      43             :   uchar                    csv_buf[ OSTREAM_BUFSZ ];
      44             : 
      45             :   int want_manifest;
      46             :   int want_accounts;
      47             :   int has_fail;
      48             : };
      49             : 
      50             : typedef struct fd_snapshot_dumper fd_snapshot_dumper_t;
      51             : 
      52             : static fd_snapshot_dumper_t *
      53           0 : fd_snapshot_dumper_new( void * mem ) {
      54           0 :   fd_snapshot_dumper_t * dumper = mem;
      55           0 :   *dumper = (fd_snapshot_dumper_t) {
      56           0 :     .snapshot_fd = -1,
      57           0 :     .yaml_fd     = -1,
      58           0 :     .csv_fd      = -1
      59           0 :   };
      60           0 :   return dumper;
      61           0 : }
      62             : 
      63             : static void *
      64           0 : fd_snapshot_dumper_delete( fd_snapshot_dumper_t * dumper ) {
      65             : 
      66           0 :   if( dumper->loader ) {
      67           0 :     fd_snapshot_loader_delete( dumper->loader );
      68           0 :     dumper->loader = NULL;
      69           0 :   }
      70             : 
      71           0 :   if( dumper->restore ) {
      72           0 :     fd_snapshot_restore_delete( dumper->restore );
      73           0 :     dumper->restore = NULL;
      74           0 :   }
      75             : 
      76           0 :   if( dumper->slot_ctx ) {
      77           0 :     fd_exec_slot_ctx_delete( fd_exec_slot_ctx_leave( dumper->slot_ctx ) );
      78           0 :     dumper->slot_ctx = NULL;
      79           0 :   }
      80             : 
      81           0 :   if( dumper->epoch_ctx ) {
      82           0 :     fd_exec_epoch_ctx_delete( fd_exec_epoch_ctx_leave( dumper->epoch_ctx ) );
      83           0 :     dumper->epoch_ctx = NULL;
      84           0 :   }
      85             : 
      86           0 :   if( dumper->acc_mgr ) {
      87           0 :     fd_acc_mgr_delete( dumper->acc_mgr );
      88           0 :     dumper->acc_mgr = NULL;
      89           0 :   }
      90             : 
      91           0 :   if( dumper->funk ) {
      92           0 :     fd_wksp_free_laddr( fd_funk_delete( fd_funk_leave( dumper->funk ) ) );
      93           0 :     dumper->funk = NULL;
      94           0 :   }
      95             : 
      96           0 :   if( dumper->alloc ) {
      97           0 :     fd_wksp_free_laddr( fd_alloc_delete( fd_alloc_leave( dumper->alloc ) ) );
      98           0 :     dumper->alloc = NULL;
      99           0 :   }
     100             : 
     101           0 :   if( dumper->yaml_fd>=0 ) {
     102           0 :     if( FD_UNLIKELY( 0!=close( dumper->yaml_fd ) ) )
     103           0 :       FD_LOG_WARNING(( "close(%d) failed (%d-%s)", dumper->yaml_fd, errno, fd_io_strerror( errno ) ));
     104           0 :     dumper->yaml_fd = -1;
     105           0 :   }
     106             : 
     107           0 :   if( dumper->csv_fd>=0 ) {
     108           0 :     fd_io_buffered_ostream_fini( &dumper->csv_out );
     109           0 :     if( FD_UNLIKELY( 0!=close( dumper->csv_fd ) ) )
     110           0 :       FD_LOG_WARNING(( "close(%d) failed (%d-%s)", dumper->csv_fd, errno, fd_io_strerror( errno ) ));
     111           0 :     dumper->csv_fd = -1;
     112           0 :   }
     113             : 
     114           0 :   fd_memset( dumper, 0, sizeof(fd_snapshot_dumper_t) );
     115           0 :   return dumper;
     116           0 : }
     117             : 
     118             : /* fd_snapshot_dumper_on_manifest gets called when the snapshot manifest
     119             :    becomes available. */
     120             : 
     121             : static int
     122             : fd_snapshot_dumper_on_manifest( void *                 _d,
     123             :                                 fd_solana_manifest_t * manifest,
     124           0 :                                 fd_spad_t *            spad ) {
     125           0 :   fd_snapshot_dumper_t * d = _d;
     126           0 :   if( !d->want_manifest ) return 0;
     127           0 :   d->want_manifest = 0;
     128             : 
     129           0 :   FILE * file = fdopen( d->yaml_fd, "w" );
     130           0 :   if( FD_UNLIKELY( !file ) ) {
     131           0 :     FD_LOG_WARNING(( "fdopen(%d) failed (%d-%s)", d->yaml_fd, errno, fd_io_strerror( errno ) ));
     132           0 :     close( d->yaml_fd );
     133           0 :     d->yaml_fd  = -1;
     134           0 :     d->has_fail = 1;
     135           0 :     return errno;
     136           0 :   }
     137             : 
     138           0 :   fd_spad_push( spad );
     139           0 :   fd_flamenco_yaml_t * yaml = fd_flamenco_yaml_init( fd_flamenco_yaml_new( fd_spad_alloc( spad, fd_flamenco_yaml_align(), fd_flamenco_yaml_footprint() ) ), file );
     140           0 :   fd_solana_manifest_walk( yaml, manifest, fd_flamenco_yaml_walk, NULL, 0U );
     141           0 :   fd_flamenco_yaml_delete( yaml );
     142           0 :   fd_spad_pop( spad );
     143             : 
     144           0 :   int err = 0;
     145           0 :   if( FD_UNLIKELY( (err = ferror( file )) ) ) {
     146           0 :     FD_LOG_WARNING(( "Error occurred while writing manifest (%d-%s)", err, fd_io_strerror( err ) ));
     147           0 :     d->has_fail = 1;
     148           0 :   }
     149             : 
     150           0 :   fclose( file );
     151           0 :   close( d->yaml_fd );
     152           0 :   d->yaml_fd = -1;
     153           0 :   return err;
     154           0 : }
     155             : 
     156             : /* fd_snapshot_dumper_record processes a newly encountered account
     157             :    record. */
     158             : 
     159             : union fd_snapshot_csv_rec {
     160             :   char line[ 180 ];
     161             :   struct __attribute__((packed)) {
     162             :     char acct_addr[ FD_BASE58_ENCODED_32_LEN ];
     163             :     char comma1;
     164             :     char owner_addr[ FD_BASE58_ENCODED_32_LEN ];
     165             :     char comma2;
     166             :     char hash[ FD_BASE58_ENCODED_32_LEN ];
     167             :     char comma3;
     168             :     char slot[ 14 ];  /* enough for 10000 years at 400ms slot time */
     169             :     char comma4;
     170             :     char size[ 8 ];  /* can represent [0,10<<20) */
     171             :     char comma5;
     172             :     char lamports[ 20 ];  /* can represent [0,1<<64) */
     173             :     char newline;
     174             :   };
     175             : };
     176             : 
     177             : typedef union fd_snapshot_csv_rec fd_snapshot_csv_rec_t;
     178             : 
     179             : static void
     180             : fd_snapshot_dumper_record( fd_snapshot_dumper_t * d,
     181             :                            fd_funk_rec_t const *  rec,
     182           0 :                            fd_wksp_t *            wksp ) {
     183             : 
     184           0 :   uchar const *             rec_val = fd_funk_val_const( rec, wksp );
     185           0 :   fd_account_meta_t const * meta    = (fd_account_meta_t const *)rec_val;
     186             :   //uchar const *             data    = rec_val + meta->hlen;
     187             : 
     188           0 :   if( d->csv_fd>=0 ) {
     189           0 :     fd_snapshot_csv_rec_t csv_rec;
     190           0 :     fd_memset( &csv_rec, ' ', sizeof(csv_rec) );
     191             : 
     192           0 :     ulong b58sz;
     193           0 :     fd_base58_encode_32( fd_funk_key_to_acc( rec->pair.key )->uc, &b58sz, csv_rec.acct_addr );
     194           0 :     csv_rec.line[ offsetof(fd_snapshot_csv_rec_t,acct_addr)+b58sz ] = ' ';
     195           0 :     csv_rec.comma1 = ',';
     196             : 
     197           0 :     fd_base58_encode_32( meta->info.owner, &b58sz, csv_rec.owner_addr );
     198           0 :     csv_rec.line[ offsetof(fd_snapshot_csv_rec_t,owner_addr)+b58sz ] = ' ';
     199           0 :     csv_rec.comma2 = ',';
     200             : 
     201           0 :     fd_base58_encode_32( meta->hash, &b58sz, csv_rec.hash );
     202           0 :     csv_rec.line[ offsetof(fd_snapshot_csv_rec_t,hash)+b58sz ] = ' ';
     203           0 :     csv_rec.comma3 = ',';
     204             : 
     205           0 :     fd_cstr_append_ulong_as_text( csv_rec.slot, ' ', '\0', meta->dlen, 15 );
     206           0 :     csv_rec.comma4 = ',';
     207             : 
     208           0 :     fd_cstr_append_ulong_as_text( csv_rec.size, ' ', '\0', meta->dlen, 8 );
     209           0 :     csv_rec.comma5 = ',';
     210             : 
     211           0 :     fd_cstr_append_ulong_as_text( csv_rec.lamports, ' ', '\0', meta->info.lamports, 20 );
     212           0 :     csv_rec.newline = '\n';
     213             : 
     214           0 :     fd_io_buffered_ostream_write( &d->csv_out, csv_rec.line, sizeof(csv_rec.line) );
     215           0 :   }
     216           0 : }
     217             : 
     218             : /* fd_snapshot_dumper_release visits any newly appeared accounts and
     219             :    removes their records from the database. */
     220             : 
     221             : static int
     222           0 : fd_snapshot_dumper_release( fd_snapshot_dumper_t * d ) {
     223             : 
     224           0 :   fd_funk_txn_t *      funk_txn = d->restore->funk_txn;
     225           0 :   fd_funk_txn_xid_t    txn_xid  = funk_txn->xid;
     226           0 :   fd_funk_t *          funk     = d->funk;
     227           0 :   fd_wksp_t *          wksp     = fd_funk_wksp( funk );
     228           0 :   fd_funk_rec_t *      rec_map  = fd_funk_rec_map( funk, wksp );
     229             : 
     230             :   /* Dump all the records */
     231           0 :   for( fd_funk_rec_t const * rec = fd_funk_txn_rec_head( funk_txn, rec_map );
     232           0 :                              rec;
     233           0 :                              rec = fd_funk_rec_next( rec, rec_map ) ) {
     234           0 :     if( FD_UNLIKELY( !fd_funk_key_is_acc( rec->pair.key ) ) ) continue;
     235           0 :     fd_snapshot_dumper_record( d, rec, wksp );
     236           0 :   }
     237             : 
     238             :   /* In order to save heap space, evict all the accounts we just
     239             :      visited.  We can do this because we know we'll never read them
     240             :      again. */
     241             : 
     242           0 :   if( FD_UNLIKELY( fd_funk_txn_cancel( funk, funk_txn, 1 )!=1UL ) )
     243           0 :     FD_LOG_ERR(( "Failed to cancel funk txn" ));  /* unreachable */
     244             : 
     245           0 :   funk_txn = fd_funk_txn_prepare( funk, NULL, &txn_xid, 1 );
     246           0 :   if( FD_UNLIKELY( !funk_txn ) )
     247           0 :     FD_LOG_ERR(( "Failed to prepare funk txn" ));  /* unreachable */
     248             : 
     249           0 :   d->restore->funk_txn = funk_txn;
     250           0 :   return 0;
     251           0 : }
     252             : 
     253             : /* fd_snapshot_dumper_advance polls the tar reader for data and handles
     254             :    any newly appeared accounts. */
     255             : 
     256             : static int
     257           0 : fd_snapshot_dumper_advance( fd_snapshot_dumper_t * dumper ) {
     258             : 
     259           0 :   int advance_err = fd_snapshot_loader_advance( dumper->loader );
     260           0 :   if( FD_UNLIKELY( advance_err<0 ) ) return advance_err;
     261             : 
     262           0 :   int collect_err = fd_snapshot_dumper_release( dumper );
     263           0 :   if( FD_UNLIKELY( collect_err ) ) return collect_err;
     264             : 
     265           0 :   return 0;
     266           0 : }
     267             : 
     268             : /* fd_snapshot_dump_args_t contains the command-line arguments for the
     269             :    dump command. */
     270             : 
     271             : struct fd_snapshot_dump_args {
     272             :   char const * _page_sz;
     273             :   ulong        page_cnt;
     274             :   ulong        near_cpu;
     275             :   ulong        zstd_window_sz;
     276             :   char *       snapshot;
     277             :   char const * manifest_path;
     278             :   char const * csv_path;
     279             :   int          csv_hdr;
     280             :   ushort       http_redirs;
     281             : };
     282             : 
     283             : typedef struct fd_snapshot_dump_args fd_snapshot_dump_args_t;
     284             : 
     285             : static int
     286             : do_dump( fd_snapshot_dumper_t *    d,
     287             :          fd_snapshot_dump_args_t * args,
     288             :          fd_wksp_t *               wksp,
     289           0 :          fd_spad_t *               spad ) {
     290             : 
     291             :   /* Resolve snapshot source */
     292             : 
     293           0 :   fd_snapshot_src_t src[1];
     294           0 :   if( FD_UNLIKELY( !fd_snapshot_src_parse( src, args->snapshot ) ) )
     295           0 :     return EXIT_FAILURE;
     296             : 
     297             :   /* Create a heap */
     298             : 
     299           0 :   ulong const fd_alloc_tag = 41UL;
     300           0 :   d->alloc = fd_alloc_join( fd_alloc_new( fd_wksp_alloc_laddr( wksp, fd_alloc_align(), fd_alloc_footprint(), fd_alloc_tag ), fd_alloc_tag ), 0UL );
     301           0 :   if( FD_UNLIKELY( !d->alloc ) ) { FD_LOG_WARNING(( "fd_alloc_join() failed" )); return EXIT_FAILURE; }
     302             : 
     303           0 :   fd_wksp_usage_t wksp_usage[1] = {0};
     304           0 :   fd_wksp_usage( wksp, NULL, 0UL, wksp_usage );
     305             : 
     306           0 :   if( args->csv_path ) {
     307           0 :     d->csv_fd = open( args->csv_path, O_WRONLY|O_CREAT|O_TRUNC, 0644 );
     308           0 :     if( FD_UNLIKELY( d->csv_fd<0 ) ) { FD_LOG_WARNING(( "open(%s) failed (%d-%s)", args->csv_path, errno, fd_io_strerror( errno ) )); return EXIT_FAILURE; }
     309           0 :     fd_io_buffered_ostream_init( &d->csv_out, d->csv_fd, d->csv_buf, OSTREAM_BUFSZ );
     310           0 :   }
     311             : 
     312           0 :   if( args->manifest_path ) {
     313           0 :     d->yaml_fd = open( args->manifest_path, O_WRONLY|O_CREAT|O_TRUNC, 0644 );
     314           0 :     if( FD_UNLIKELY( d->yaml_fd<0 ) ) { FD_LOG_WARNING(( "open(%s) failed (%d-%s)", args->manifest_path, errno, fd_io_strerror( errno ) )); return EXIT_FAILURE; }
     315           0 :   }
     316             : 
     317             :   /* Create loader */
     318             : 
     319           0 :   d->loader = fd_snapshot_loader_new( fd_spad_alloc( spad, fd_snapshot_loader_align(), fd_snapshot_loader_footprint( args->zstd_window_sz ) ), args->zstd_window_sz );
     320           0 :   if( FD_UNLIKELY( !d->loader ) ) { FD_LOG_WARNING(( "Failed to create fd_snapshot_loader_t" )); return EXIT_FAILURE; }
     321             : 
     322             :   /* Create a high-quality hash seed for fd_funk */
     323             : 
     324           0 :   ulong funk_seed;
     325           0 :   if( FD_UNLIKELY( sizeof(ulong)!=getrandom( &funk_seed, sizeof(ulong), 0 ) ) )
     326           0 :     { FD_LOG_WARNING(( "getrandom() failed (%d-%s)", errno, fd_io_strerror( errno ) )); return EXIT_FAILURE; }
     327             : 
     328             :   /* Create a funk database */
     329             : 
     330           0 :   ulong const txn_max =   16UL;  /* we really only need 1 */
     331           0 :   ulong const rec_max = 1024UL;  /* we evict records as we go */
     332             : 
     333           0 :   ulong funk_tag = 42UL;
     334           0 :   d->funk = fd_funk_join( fd_funk_new( fd_wksp_alloc_laddr( wksp, fd_funk_align(), fd_funk_footprint(), funk_tag ), funk_tag, funk_seed, txn_max, rec_max ) );
     335           0 :   if( FD_UNLIKELY( !d->funk ) ) { FD_LOG_WARNING(( "Failed to create fd_funk_t" )); return EXIT_FAILURE; }
     336           0 :   fd_funk_start_write( d->funk );
     337             : 
     338             :   /* Create a new processing context */
     339             : 
     340           0 :   d->acc_mgr = fd_acc_mgr_new( fd_spad_alloc( spad, FD_ACC_MGR_ALIGN, FD_ACC_MGR_FOOTPRINT ), d->funk );
     341           0 :   if( FD_UNLIKELY( !d->acc_mgr ) ) { FD_LOG_WARNING(( "Failed to create fd_acc_mgr_t" )); return EXIT_FAILURE; }
     342             : 
     343           0 :   ulong const vote_acct_max = 1UL;  /* fd_snapshot doesn't retain epoch stakes */
     344           0 :   d->epoch_ctx = fd_exec_epoch_ctx_join( fd_exec_epoch_ctx_new( fd_spad_alloc( spad, fd_exec_epoch_ctx_align(), fd_exec_epoch_ctx_footprint( vote_acct_max ) ), vote_acct_max ) );
     345           0 :   if( FD_UNLIKELY( !d->epoch_ctx ) ) { FD_LOG_WARNING(( "Failed to create fd_exec_epoch_ctx_t" )); return EXIT_FAILURE; }
     346             : 
     347           0 :   d->slot_ctx = fd_exec_slot_ctx_join( fd_exec_slot_ctx_new( fd_spad_alloc( spad, FD_EXEC_SLOT_CTX_ALIGN, FD_EXEC_SLOT_CTX_FOOTPRINT ), spad ) );
     348           0 :   if( FD_UNLIKELY( !d->slot_ctx ) ) { FD_LOG_WARNING(( "Failed to create fd_exec_slot_ctx_t" )); return EXIT_FAILURE; }
     349             : 
     350           0 :   d->slot_ctx->acc_mgr   = d->acc_mgr;
     351           0 :   d->slot_ctx->epoch_ctx = d->epoch_ctx;
     352             : 
     353             :   /* funk_txn is destroyed automatically when deleting fd_funk_t. */
     354             : 
     355           0 :   fd_funk_txn_xid_t funk_txn_xid = { .ul = { 1UL } };
     356           0 :   fd_funk_txn_t * funk_txn = fd_funk_txn_prepare( d->funk, NULL, &funk_txn_xid, 1 );
     357           0 :   d->slot_ctx->funk_txn = funk_txn;
     358             : 
     359           0 :   void * restore_mem = fd_spad_alloc( spad, fd_snapshot_restore_align(), fd_snapshot_restore_footprint() );
     360           0 :   if( FD_UNLIKELY( !restore_mem ) ) FD_LOG_ERR(( "Failed to allocate restore buffer" ));  /* unreachable */
     361             : 
     362           0 :   d->restore = fd_snapshot_restore_new( restore_mem, d->acc_mgr, funk_txn, spad, d, fd_snapshot_dumper_on_manifest, NULL, NULL );
     363           0 :   if( FD_UNLIKELY( !d->restore ) ) { FD_LOG_WARNING(( "Failed to create fd_snapshot_restore_t" )); return EXIT_FAILURE; }
     364             : 
     365             :   /* Set up the snapshot loader */
     366             : 
     367           0 :   if( FD_UNLIKELY( !fd_snapshot_loader_init( d->loader, d->restore, src, 0UL, 1 ) ) ) {
     368           0 :     FD_LOG_WARNING(( "fd_snapshot_loader_init failed" ));
     369           0 :     return EXIT_FAILURE;
     370           0 :   }
     371             : 
     372           0 :   d->want_manifest = (!!args->manifest_path);
     373           0 :   d->want_accounts = (!!args->csv_path);
     374             : 
     375           0 :   if( FD_UNLIKELY( (!d->want_manifest) & (!d->want_accounts) ) ) {
     376           0 :     FD_LOG_NOTICE(( "Nothing to do, exiting." ));
     377           0 :     return EXIT_SUCCESS;
     378           0 :   }
     379             : 
     380           0 :   if( (d->csv_fd>=0) & (args->csv_hdr) ) {
     381           0 :     fd_snapshot_csv_rec_t csv_rec;
     382           0 :     memset( &csv_rec, ' ', sizeof(fd_snapshot_csv_rec_t) );
     383           0 :     memcpy( csv_rec.acct_addr,  "address",  strlen( "address"  ) );
     384           0 :     memcpy( csv_rec.owner_addr, "owner",    strlen( "owner"    ) );
     385           0 :     memcpy( csv_rec.hash,       "hash",     strlen( "hash"     ) );
     386           0 :     memcpy( csv_rec.slot,       "slot",     strlen( "slot"     ) );
     387           0 :     memcpy( csv_rec.size,       "size",     strlen( "size"     ) );
     388           0 :     memcpy( csv_rec.lamports,   "lamports", strlen( "lamports" ) );
     389           0 :     csv_rec.comma1  = ',';
     390           0 :     csv_rec.comma2  = ',';
     391           0 :     csv_rec.comma3  = ',';
     392           0 :     csv_rec.comma4  = ',';
     393           0 :     csv_rec.comma5  = ',';
     394           0 :     csv_rec.newline = '\n';
     395             : 
     396           0 :     if( FD_UNLIKELY( write( d->csv_fd, csv_rec.line, sizeof(fd_snapshot_csv_rec_t) )
     397           0 :                      != sizeof(fd_snapshot_csv_rec_t) ) ) {
     398           0 :       FD_LOG_WARNING(( "Failed to write CSV header (%d-%s)", errno, fd_io_strerror( errno ) ));
     399           0 :       d->has_fail = 1;
     400           0 :       return EXIT_FAILURE;
     401           0 :     }
     402           0 :   }
     403             : 
     404           0 :   for(;;) {
     405           0 :     int err = fd_snapshot_dumper_advance( d );
     406           0 :     if( err==0 )     { /* ok */ }
     407           0 :     else if( err<0 ) { /* EOF */ break; }
     408           0 :     else             { return EXIT_FAILURE; }
     409             : 
     410           0 :     if( FD_UNLIKELY( (!d->want_accounts) & (!d->want_manifest) ) )
     411           0 :       break;
     412           0 :   }
     413             : 
     414           0 :   return d->has_fail ? EXIT_FAILURE : EXIT_SUCCESS;
     415           0 : }
     416             : 
     417             : int
     418             : cmd_dump( int     argc,
     419           0 :           char ** argv ) {
     420             : 
     421           0 :   fd_snapshot_dump_args_t args[1] = {{0}};
     422           0 :   args->_page_sz       =         fd_env_strip_cmdline_cstr  ( &argc, &argv, "--page-sz",        NULL,      "gigantic" );
     423           0 :   args->page_cnt       =         fd_env_strip_cmdline_ulong ( &argc, &argv, "--page-cnt",       NULL,             3UL );
     424           0 :   args->near_cpu       =         fd_env_strip_cmdline_ulong ( &argc, &argv, "--near-cpu",       NULL, fd_log_cpu_id() );
     425           0 :   args->zstd_window_sz =         fd_env_strip_cmdline_ulong ( &argc, &argv, "--zstd-window-sz", NULL,      33554432UL );
     426           0 :   args->snapshot       = (char *)fd_env_strip_cmdline_cstr  ( &argc, &argv, "--snapshot",       NULL,            NULL );
     427           0 :   args->manifest_path  =         fd_env_strip_cmdline_cstr  ( &argc, &argv, "--manifest",       NULL,            NULL );
     428           0 :   args->csv_path       =         fd_env_strip_cmdline_cstr  ( &argc, &argv, "--csv",            NULL,            NULL );
     429           0 :   args->csv_hdr        =         fd_env_strip_cmdline_int   ( &argc, &argv, "--csv-hdr",        NULL,               1 );
     430           0 :   args->http_redirs    = (ushort)fd_env_strip_cmdline_ushort( &argc, &argv, "--http-redirs",    NULL,               5 );
     431             : 
     432           0 :   if( FD_UNLIKELY( argc!=1 ) )
     433           0 :     FD_LOG_ERR(( "Unexpected command-line arguments" ));
     434           0 :   if( FD_UNLIKELY( !args->snapshot ) )
     435           0 :     FD_LOG_ERR(( "Missing --snapshot argument" ));
     436             : 
     437           0 :   FD_LOG_NOTICE(( "Creating workspace (--page-cnt %lu, --page-sz %s)", args->page_cnt, args->_page_sz ));
     438             : 
     439             :   /* With workspace */
     440             : 
     441           0 :   fd_wksp_t * wksp = fd_wksp_new_anonymous( fd_cstr_to_shmem_page_sz( args->_page_sz ), args->page_cnt, args->near_cpu, "wksp", 0UL );
     442           0 :   if( FD_UNLIKELY( !wksp ) ) FD_LOG_ERR(( "fd_wksp_new_anonymous() failed" ));
     443             : 
     444             :   /* With spad */
     445             : 
     446           0 :   ulong       mem_max           = args->zstd_window_sz + (1<<29); /* manifest plus 512 MiB headroom */
     447           0 :   uchar *     mem               = fd_wksp_alloc_laddr(  wksp, FD_SPAD_ALIGN, FD_SPAD_FOOTPRINT( mem_max ), 1UL );
     448           0 :   fd_spad_t * spad              = fd_spad_join( fd_spad_new( mem, mem_max ) );
     449           0 :   if( FD_UNLIKELY( !spad ) ) {
     450           0 :     FD_LOG_ERR(( "Failed to allocate spad" ));
     451           0 :   }
     452           0 :   fd_spad_push( spad );
     453             : 
     454             :   /* With dump context */
     455             : 
     456           0 :   fd_snapshot_dumper_t  _dumper[1];
     457           0 :   fd_snapshot_dumper_t * dumper = fd_snapshot_dumper_new( _dumper );
     458             : 
     459           0 :   int rc = do_dump( dumper, args, wksp, spad );
     460           0 :   FD_LOG_INFO(( "Done. Cleaning up." ));
     461             : 
     462           0 :   fd_snapshot_dumper_delete( dumper );
     463             : 
     464           0 :   fd_spad_pop( spad );
     465           0 :   void * spad_mem = fd_spad_delete( fd_spad_leave( spad ) );
     466           0 :   fd_wksp_free_laddr( spad_mem );
     467             : 
     468           0 :   fd_wksp_delete_anonymous( wksp );
     469           0 :   return rc;
     470           0 : }
     471             : 
     472             : FD_IMPORT_CSTR( _help, "src/flamenco/snapshot/fd_snapshot_help.txt" );
     473             : 
     474             : __attribute__((noreturn)) static int
     475           0 : usage( int code ) {
     476           0 :   fwrite( _help, 1, _help_sz, stderr );
     477           0 :   fflush( stderr );
     478           0 :   exit( code );
     479           0 : }
     480             : 
     481             : int
     482             : main( int     argc,
     483             :       char ** argv ) {
     484             :   fd_boot( &argc, &argv );
     485             : 
     486             :   if( argc==1 ) return usage(1);
     487             :   if( 0==strcmp( argv[1], "help" ) ) return usage(0);
     488             :   for( int i=1; i<argc; i++ )
     489             :     if( 0==strcmp( argv[i], "--help" ) )
     490             :       return usage(0);
     491             : 
     492             :   argc--; argv++;
     493             :   char const * cmd = argv[0];
     494             : 
     495             :   if( 0==strcmp( cmd, "dump" ) ) {
     496             :     return cmd_dump( argc, argv );
     497             :   } else {
     498             :     fprintf( stderr, "Unknown command: %s\n", cmd );
     499             :     return usage(1);
     500             :   }
     501             : 
     502             :   fd_halt();
     503             :   return 0;
     504             : }

Generated by: LCOV version 1.14