LCOV - code coverage report
Current view: top level - app/firedancer-dev/commands - snapshot_load.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 666 0.0 %
Date: 2025-12-07 04:58:33 Functions: 0 13 0.0 %

          Line data    Source code
       1             : #include "../../firedancer/topology.h"
       2             : #include "../../platform/fd_sys_util.h"
       3             : #include "../../shared/commands/configure/configure.h"
       4             : #include "../../shared/commands/run/run.h"
       5             : #include "../../shared_dev/commands/dev.h"
       6             : #include "../../../disco/metrics/fd_metrics.h"
       7             : #include "../../../disco/topo/fd_topob.h"
       8             : #include "../../../disco/pack/fd_pack.h"
       9             : #include "../../../disco/pack/fd_pack_cost.h"
      10             : #include "../../../util/pod/fd_pod_format.h"
      11             : #include "../../../discof/restore/utils/fd_ssctrl.h"
      12             : #include "../../../discof/restore/utils/fd_ssmsg.h"
      13             : #include "../../../flamenco/accdb/fd_accdb_fsck.h"
      14             : #include "../../../funk/fd_funk.h"
      15             : #include "../../../vinyl/fd_vinyl.h"
      16             : #include "../../../tango/cnc/fd_cnc.h"
      17             : #include "../../../ballet/lthash/fd_lthash.h"
      18             : 
      19             : #include <errno.h>
      20             : #include <fcntl.h> /* open */
      21             : #include <sys/resource.h>
      22             : #include <linux/capability.h>
      23             : #include <unistd.h> /* close, sleep */
      24             : #include <stdio.h>
      25             : 
      26             : #define NAME "snapshot-load"
      27             : 
      28             : extern fd_topo_obj_callbacks_t * CALLBACKS[];
      29             : 
      30             : fd_topo_run_tile_t
      31             : fdctl_tile_run( fd_topo_tile_t const * tile );
      32             : 
      33             : static void
      34             : snapshot_load_topo( config_t * config,
      35           0 :                     _Bool      vinyl_server ) {
      36           0 :   fd_topo_t * topo = &config->topo;
      37           0 :   fd_topob_new( &config->topo, config->name );
      38           0 :   topo->max_page_size = fd_cstr_to_shmem_page_sz( config->hugetlbfs.max_page_size );
      39             : 
      40           0 :   fd_topob_wksp( topo, "txncache" );
      41           0 :   fd_topo_obj_t * txncache_obj = setup_topo_txncache( topo, "txncache",
      42           0 :       config->firedancer.runtime.max_live_slots,
      43           0 :       fd_ulong_pow2_up( FD_PACK_MAX_TXNCACHE_TXN_PER_SLOT ) );
      44           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, txncache_obj->id, "txncache" ) );
      45             : 
      46           0 :   fd_topob_wksp( topo, "funk" );
      47           0 :   fd_topo_obj_t * funk_obj = setup_topo_funk( topo, "funk",
      48           0 :       config->firedancer.funk.max_account_records,
      49           0 :       config->firedancer.funk.max_database_transactions,
      50           0 :       config->firedancer.funk.heap_size_gib );
      51             : 
      52           0 :   int snapshot_lthash_disabled = config->development.snapshots.disable_lthash_verification;
      53           0 :   ulong lta_tile_cnt           = config->firedancer.layout.snapla_tile_count;
      54             : 
      55           0 :   if( config->firedancer.vinyl.enabled ) {
      56           0 :     setup_topo_vinyl_meta( topo, &config->firedancer );
      57           0 :   }
      58             : 
      59           0 :   if( vinyl_server ) {
      60             :     /* Create a workspace with 512 MiB of free space for clients to
      61             :        create objects in. */
      62           0 :     fd_topo_wksp_t * server_wksp = fd_topob_wksp( topo, "vinyl_server" );
      63           0 :     server_wksp->min_part_max = 64UL;
      64           0 :     server_wksp->min_loose_sz = 64UL<<20;
      65           0 :   }
      66             : 
      67             :   /* metrics tile *****************************************************/
      68           0 :   fd_topob_wksp( topo, "metric_in" );
      69           0 :   fd_topob_wksp( topo, "metric" );
      70           0 :   fd_topob_tile( topo, "metric",  "metric", "metric_in", ULONG_MAX, 0, 0 );
      71             : 
      72             :   /* read() tile */
      73           0 :   fd_topob_wksp( topo, "snapct" );
      74           0 :   fd_topo_tile_t * snapct_tile = fd_topob_tile( topo, "snapct", "snapct", "metric_in", ULONG_MAX, 0, 0 );
      75           0 :   snapct_tile->allow_shutdown = 1;
      76             : 
      77             :   /* load tile */
      78           0 :   fd_topob_wksp( topo, "snapld" );
      79           0 :   fd_topo_tile_t * snapld_tile = fd_topob_tile( topo, "snapld", "snapld", "metric_in", ULONG_MAX, 0, 0 );
      80           0 :   snapld_tile->allow_shutdown = 1;
      81             : 
      82             :   /* "snapdc": Zstandard decompress tile */
      83           0 :   fd_topob_wksp( topo, "snapdc" );
      84           0 :   fd_topo_tile_t * snapdc_tile = fd_topob_tile( topo, "snapdc", "snapdc", "metric_in", ULONG_MAX, 0, 0 );
      85           0 :   snapdc_tile->allow_shutdown = 1;
      86             : 
      87             :   /* "snapin": Snapshot parser tile */
      88           0 :   fd_topob_wksp( topo, "snapin" );
      89           0 :   fd_topo_tile_t * snapin_tile = fd_topob_tile( topo, "snapin", "snapin", "metric_in", ULONG_MAX, 0, 0 );
      90           0 :   snapin_tile->allow_shutdown = 1;
      91             : 
      92             :   /* "snapwr": Snapshot writer tile */
      93           0 :   int vinyl_enabled = config->firedancer.vinyl.enabled;
      94           0 :   fd_topo_tile_t * snapwr_tile = NULL;
      95           0 :   if( vinyl_enabled ) {
      96           0 :     fd_topob_wksp( topo, "snapwh" );
      97           0 :     fd_topo_tile_t * snapwh_tile = fd_topob_tile( topo, "snapwh", "snapwh", "metric_in", ULONG_MAX, 0, 0 );
      98           0 :     snapwh_tile->allow_shutdown = 1;
      99             : 
     100           0 :     fd_topob_wksp( topo, "snapwr" );
     101           0 :     snapwr_tile = fd_topob_tile( topo, "snapwr", "snapwr", "metric_in", ULONG_MAX, 0, 0 );
     102           0 :     snapwr_tile->allow_shutdown = 1;
     103           0 :   }
     104             : 
     105           0 :   fd_topob_wksp( topo, "snapct_ld"    );
     106           0 :   fd_topob_wksp( topo, "snapld_dc"    );
     107           0 :   fd_topob_wksp( topo, "snapdc_in"    );
     108           0 :   if( FD_UNLIKELY( snapshot_lthash_disabled ) ) {
     109           0 :     fd_topob_wksp( topo, "snapin_ct" );
     110           0 :   }
     111           0 :   fd_topob_wksp( topo, "snapin_manif" );
     112           0 :   fd_topob_wksp( topo, "snapct_repr"  );
     113           0 :   if( vinyl_enabled ) {
     114           0 :     fd_topob_wksp( topo, "snapin_wr" );
     115           0 :   }
     116             : 
     117           0 :   if( FD_LIKELY( !snapshot_lthash_disabled ) ) {
     118           0 :     fd_topob_wksp( topo, "snapla"    );
     119           0 :     fd_topob_wksp( topo, "snapls"    );
     120           0 :     fd_topob_wksp( topo, "snapla_ls" );
     121           0 :     fd_topob_wksp( topo, "snapin_ls" );
     122           0 :     fd_topob_wksp( topo, "snapls_ct" );
     123           0 :   }
     124             : 
     125           0 : #define FOR(cnt) for( ulong i=0UL; i<cnt; i++ )
     126             : 
     127           0 :   if( FD_LIKELY( !snapshot_lthash_disabled ) ) {
     128           0 :     FOR(lta_tile_cnt)  fd_topob_tile( topo, "snapla", "snapla", "metric_in", ULONG_MAX, 0, 0 )->allow_shutdown = 1;
     129           0 :     /**/               fd_topob_tile( topo, "snapls", "snapls", "metric_in", ULONG_MAX, 0, 0 )->allow_shutdown = 1;
     130           0 :   }
     131             : 
     132           0 :   fd_topob_link( topo, "snapct_ld",   "snapct_ld",     128UL,   sizeof(fd_ssctrl_init_t),       1UL );
     133           0 :   fd_topob_link( topo, "snapld_dc",   "snapld_dc",     16384UL, USHORT_MAX,                     1UL );
     134           0 :   fd_topob_link( topo, "snapdc_in",   "snapdc_in",     16384UL, USHORT_MAX,                     1UL );
     135           0 :   if( FD_UNLIKELY( snapshot_lthash_disabled ) ) {
     136           0 :     fd_topob_link( topo, "snapin_ct", "snapin_ct",     128UL,   0UL,                            1UL );
     137           0 :   }
     138           0 :   fd_topob_link( topo, "snapin_manif", "snapin_manif", 4UL,     sizeof(fd_snapshot_manifest_t), 1UL )->permit_no_consumers = 1;
     139           0 :   fd_topob_link( topo, "snapct_repr", "snapct_repr",   128UL,   0UL,                            1UL )->permit_no_consumers = 1;
     140           0 :   if( vinyl_enabled ) {
     141           0 :     fd_topo_link_t * snapin_wh = fd_topob_link( topo, "snapin_wh", "snapin_wr", 4UL, 16UL<<20, 1UL );
     142           0 :     fd_topob_link( topo, "snapwh_wr", "snapin_wr", 4UL, 0UL,      1UL );
     143           0 :     fd_pod_insertf_ulong( topo->props, 8UL, "obj.%lu.app_sz",  snapin_wh->dcache_obj_id );
     144           0 :   }
     145             : 
     146           0 :   if( FD_LIKELY( !snapshot_lthash_disabled ) ) {
     147           0 :     FOR(lta_tile_cnt) fd_topob_link( topo, "snapla_ls",  "snapla_ls",   128UL,  sizeof(fd_lthash_value_t),          1UL );
     148           0 :     /**/              fd_topob_link( topo, "snapin_ls",  "snapin_ls",   256UL,  sizeof(fd_snapshot_full_account_t), 1UL );
     149           0 :     /**/              fd_topob_link( topo, "snapls_ct",  "snapls_ct",   128UL,  0UL,                                1UL );
     150           0 :   }
     151             : 
     152           0 :   if( FD_UNLIKELY( snapshot_lthash_disabled ) ) {
     153           0 :     fd_topob_tile_in ( topo, "snapct",  0UL, "metric_in", "snapin_ct",  0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     154           0 :   } else {
     155           0 :     fd_topob_tile_in ( topo, "snapct",  0UL, "metric_in", "snapls_ct", 0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     156           0 :   }
     157           0 :   fd_topob_tile_in ( topo, "snapct",  0UL, "metric_in", "snapld_dc",    0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     158           0 :   fd_topob_tile_out( topo, "snapct",  0UL,              "snapct_ld",    0UL                                       );
     159           0 :   fd_topob_tile_out( topo, "snapct",  0UL,              "snapct_repr",  0UL                                       );
     160           0 :   fd_topob_tile_in ( topo, "snapld",  0UL, "metric_in", "snapct_ld",    0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     161           0 :   fd_topob_tile_out( topo, "snapld",  0UL,              "snapld_dc",    0UL                                       );
     162           0 :   fd_topob_tile_in ( topo, "snapdc",  0UL, "metric_in", "snapld_dc",    0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     163           0 :   fd_topob_tile_out( topo, "snapdc",  0UL,              "snapdc_in",    0UL                                       );
     164           0 :   fd_topob_tile_in ( topo, "snapin",  0UL, "metric_in", "snapdc_in",    0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     165           0 :   if( FD_UNLIKELY( snapshot_lthash_disabled ) ) {
     166           0 :     fd_topob_tile_out( topo, "snapin", 0UL,             "snapin_ct",    0UL                                       );
     167           0 :   } else {
     168           0 :     fd_topob_tile_out( topo, "snapin", 0UL,             "snapin_ls",   0UL                                       );
     169           0 :   }
     170           0 :   fd_topob_tile_out( topo, "snapin",  0UL,              "snapin_manif", 0UL                                       );
     171           0 :   if( vinyl_enabled ) {
     172           0 :     fd_topob_tile_out( topo, "snapin", 0UL,              "snapin_wh", 0UL );
     173           0 :     fd_topob_tile_in ( topo, "snapwh", 0UL, "metric_in", "snapin_wh", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     174           0 :     fd_topob_tile_out( topo, "snapwh", 0UL,              "snapwh_wr", 0UL );
     175           0 :     fd_topob_tile_in ( topo, "snapwr", 0UL, "metric_in", "snapwh_wr", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     176           0 :     fd_topob_tile_uses( topo, snapwr_tile, &topo->objs[ topo->links[ fd_topo_find_link( topo, "snapin_wh", 0UL ) ].dcache_obj_id ], FD_SHMEM_JOIN_MODE_READ_ONLY );
     177           0 :   }
     178           0 :   if( FD_LIKELY( !snapshot_lthash_disabled ) ) {
     179           0 :     FOR(lta_tile_cnt) fd_topob_tile_in ( topo, "snapla", i,   "metric_in", "snapdc_in",  0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     180           0 :     FOR(lta_tile_cnt) fd_topob_tile_out( topo, "snapla", i,                "snapla_ls",  i                                         );
     181           0 :     /**/              fd_topob_tile_in ( topo, "snapls", 0UL, "metric_in", "snapin_ls",  0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     182           0 :     FOR(lta_tile_cnt) fd_topob_tile_in ( topo, "snapls", 0UL, "metric_in", "snapla_ls",  i,   FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     183           0 :     /**/              fd_topob_tile_out( topo, "snapls", 0UL,              "snapls_ct",  0UL                                       );
     184           0 :   }
     185             : 
     186             :   /* snapin funk / txncache access */
     187           0 :   fd_topob_tile_uses( topo, snapin_tile, funk_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     188           0 :   fd_topob_tile_uses( topo, snapin_tile, txncache_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     189           0 :   snapin_tile->snapin.funk_obj_id     = funk_obj->id;
     190           0 :   snapin_tile->snapin.txncache_obj_id = txncache_obj->id;
     191           0 :   if( config->firedancer.vinyl.enabled ) {
     192           0 :     ulong vinyl_map_obj_id  = fd_pod_query_ulong( topo->props, "vinyl.meta_map",  ULONG_MAX ); FD_TEST( vinyl_map_obj_id !=ULONG_MAX );
     193           0 :     ulong vinyl_pool_obj_id = fd_pod_query_ulong( topo->props, "vinyl.meta_pool", ULONG_MAX ); FD_TEST( vinyl_pool_obj_id!=ULONG_MAX );
     194             : 
     195           0 :     fd_topo_obj_t * vinyl_map_obj  = &topo->objs[ vinyl_map_obj_id ];
     196           0 :     fd_topo_obj_t * vinyl_pool_obj = &topo->objs[ vinyl_pool_obj_id ];
     197             : 
     198           0 :     fd_topob_tile_uses( topo, snapin_tile, vinyl_map_obj,  FD_SHMEM_JOIN_MODE_READ_WRITE );
     199           0 :     fd_topob_tile_uses( topo, snapin_tile, vinyl_pool_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     200           0 :   }
     201             : 
     202           0 :   snapin_tile->snapin.max_live_slots  = config->firedancer.runtime.max_live_slots;
     203             : 
     204           0 :   if( vinyl_server ) {
     205             :     /* Allocate a public CNC, which allows the vinyl tile to map memory
     206             :        allocated by other clients.  This is useful for flexibility
     207             :        during development, but not something we'd run in production due
     208             :        to security concerns. */
     209           0 :     fd_topo_obj_t * vinyl_cnc = fd_topob_obj( topo, "cnc", "vinyl_server" );
     210           0 :     fd_pod_insertf_ulong( topo->props, FD_VINYL_CNC_APP_SZ, "obj.%lu.app_sz", vinyl_cnc->id );
     211           0 :     fd_pod_insertf_ulong( topo->props, FD_VINYL_CNC_TYPE,   "obj.%lu.type",   vinyl_cnc->id );
     212           0 :     fd_pod_insert_ulong ( topo->props, "vinyl.cnc", vinyl_cnc->id );
     213             : 
     214           0 :     fd_topo_obj_t * vinyl_data = setup_topo_vinyl_cache( topo, &config->firedancer );
     215             : 
     216           0 :     fd_topob_wksp( topo, "vinyl_exec" );
     217           0 :     fd_topo_tile_t * vinyl_tile = fd_topob_tile( topo, "vinyl", "vinyl_exec", "metric_in", ULONG_MAX, 0, 0 );
     218             : 
     219           0 :     fd_topob_tile_uses( topo, vinyl_tile, vinyl_cnc,  FD_SHMEM_JOIN_MODE_READ_WRITE );
     220           0 :     fd_topob_tile_uses( topo, vinyl_tile, vinyl_data, FD_SHMEM_JOIN_MODE_READ_WRITE );
     221             : 
     222           0 :     fd_topob_tile_in( topo, "vinyl", 0UL, "metric_in", "snapin_manif", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     223           0 :   }
     224             : 
     225           0 :   for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
     226           0 :     fd_topo_tile_t * tile = &topo->tiles[ i ];
     227           0 :     fd_topo_configure_tile( tile, config );
     228           0 :   }
     229             : 
     230           0 :   fd_topob_auto_layout( topo, 0 );
     231           0 :   fd_topob_finish( topo, CALLBACKS );
     232           0 : }
     233             : 
     234             : static void
     235           0 : snapshot_load_topo1( config_t * config ) {
     236           0 :   snapshot_load_topo( config, 0 );
     237           0 : }
     238             : 
     239             : extern int * fd_log_private_shared_lock;
     240             : 
     241             : static void
     242             : snapshot_load_args( int *    pargc,
     243             :                     char *** pargv,
     244           0 :                     args_t * args ) {
     245           0 :   if( FD_UNLIKELY( fd_env_strip_cmdline_contains( pargc, pargv, "--help" ) ) ) {
     246           0 :     fputs(
     247           0 :       "\nUsage: firedancer-dev snapshot-load [GLOBAL FLAGS] [FLAGS]\n"
     248           0 :       "\n"
     249           0 :       "Global Flags:\n"
     250           0 :       "  --mainnet            Use Solana mainnet-beta defaults\n"
     251           0 :       "  --testnet            Use Solana testnet defaults\n"
     252           0 :       "  --devnet             Use Solana devnet defaults\n"
     253           0 :       "\n"
     254           0 :       "Flags:\n"
     255           0 :       "  --snapshot-dir PATH  Load/save snapshots from this directory\n"
     256           0 :       "  --offline            Do not attempt to download snapshots\n"
     257           0 :       "  --no-incremental     Disable incremental snapshot loading\n"
     258           0 :       "  --no-watch           Do not print periodic progress updates\n"
     259           0 :       "  --db <funk/vinyl>    Database engine\n"
     260           0 :       "  --db-sz <bytes>      Database size in bytes (e.g. 10e9 -> 10 GB)\n"
     261           0 :       "  --db-rec-max <num>   Database max record/account count (e.g. 10e6 -> 10M accounts)\n"
     262           0 :       "  --fsck               After loading, run database integrity checks\n"
     263           0 :       "  --lthash             After loading, recompute the account DB lthash\n"
     264           0 :       "  --accounts-hist      After loading, analyze account size distribution\n"
     265           0 :       "\n"
     266           0 :       "Vinyl database flags:\n"
     267           0 :       "  --vinyl-server         After loading, indefinitely run a vinyl DB server\n"
     268           0 :       "  --vinyl-path <path>    Path to vinyl bstream file (overrides existing files!)\n"
     269           0 :       "  --vinyl-io <backend>   Vinyl I/O backend (default: bd)\n"
     270           0 :       "  --cache-sz <bytes>     DB cache size in bytes (e.g. 1e9 -> 1 GB)\n"
     271           0 :       "  --cache-rec-max <num>  DB cache max entry count (e.g. 1e6 -> 1M cache entries)\n"
     272           0 :       "\n"
     273           0 :       "Vinyl I/O backends:\n"
     274           0 :       "  bd  readv/writev-style single-threaded blocking I/O\n"
     275           0 :       "  mm  Memory-mapped I/O\n"
     276           0 :       "\n",
     277           0 :       stderr );
     278           0 :     exit( 0 );
     279           0 :   }
     280           0 :   memset( &args->snapshot_load, 0, sizeof(args->snapshot_load) );
     281             : 
     282           0 :   char const * snapshot_dir  = fd_env_strip_cmdline_cstr    ( pargc, pargv, "--snapshot-dir", NULL, NULL   );
     283           0 :   _Bool        offline       = fd_env_strip_cmdline_contains( pargc, pargv, "--offline"                    )!=0;
     284           0 :   _Bool        no_incremental= fd_env_strip_cmdline_contains( pargc, pargv, "--no-incremental"             )!=0;
     285           0 :   _Bool        no_watch      = fd_env_strip_cmdline_contains( pargc, pargv, "--no-watch"                   )!=0;
     286           0 :   char const * db            = fd_env_strip_cmdline_cstr    ( pargc, pargv, "--db",           NULL, "funk" );
     287           0 :   float        db_sz         = fd_env_strip_cmdline_float   ( pargc, pargv, "--db-sz",        NULL, 0.0f   );
     288           0 :   float        db_rec_max    = fd_env_strip_cmdline_float   ( pargc, pargv, "--db-rec-max",   NULL, 0.0f   );
     289           0 :   _Bool        fsck          = fd_env_strip_cmdline_contains( pargc, pargv, "--fsck"                       )!=0;
     290           0 :   _Bool        fsck_lthash   = fd_env_strip_cmdline_contains( pargc, pargv, "--fsck-lthash"                )!=0;
     291           0 :   _Bool        lthash        = fd_env_strip_cmdline_contains( pargc, pargv, "--lthash"                     )!=0;
     292           0 :   _Bool        accounts_hist = fd_env_strip_cmdline_contains( pargc, pargv, "--accounts-hist"              )!=0;
     293           0 :   _Bool        vinyl_server  = fd_env_strip_cmdline_contains( pargc, pargv, "--vinyl-server"               )!=0;
     294           0 :   char const * vinyl_path    = fd_env_strip_cmdline_cstr    ( pargc, pargv, "--vinyl-path",   NULL, NULL   );
     295           0 :   char const * vinyl_io      = fd_env_strip_cmdline_cstr    ( pargc, pargv, "--vinyl-io",     NULL, "bd"   );
     296           0 :   float        cache_sz      = fd_env_strip_cmdline_float   ( pargc, pargv, "--cache-sz",     NULL, 0.0f   );
     297           0 :   float        cache_rec_max = fd_env_strip_cmdline_float   ( pargc, pargv, "--cache-rec-max",NULL, 0.0f   );
     298             : 
     299           0 :   fd_cstr_ncpy( args->snapshot_load.snapshot_dir, snapshot_dir, sizeof(args->snapshot_load.snapshot_dir) );
     300           0 :   args->snapshot_load.fsck           = fsck;
     301           0 :   args->snapshot_load.fsck_lthash    = fsck_lthash;
     302           0 :   args->snapshot_load.lthash         = lthash;
     303           0 :   args->snapshot_load.accounts_hist  = accounts_hist;
     304           0 :   args->snapshot_load.offline        = offline;
     305           0 :   args->snapshot_load.no_incremental = no_incremental;
     306           0 :   args->snapshot_load.no_watch       = no_watch;
     307           0 :   args->snapshot_load.vinyl_server   = !!vinyl_server;
     308             : 
     309           0 :   if(      0==strcmp( db, "funk"  ) ) args->snapshot_load.is_vinyl = 0;
     310           0 :   else if( 0==strcmp( db, "vinyl" ) ) args->snapshot_load.is_vinyl = 1;
     311           0 :   else FD_LOG_ERR(( "invalid --db '%s' (must be 'funk' or 'vinyl')", db ));
     312             : 
     313           0 :   args->snapshot_load.db_sz         = (ulong)db_sz;
     314           0 :   args->snapshot_load.db_rec_max    = (ulong)db_rec_max;
     315           0 :   args->snapshot_load.cache_sz      = (ulong)cache_sz;
     316           0 :   args->snapshot_load.cache_rec_max = (ulong)cache_rec_max;
     317             : 
     318           0 :   fd_cstr_ncpy( args->snapshot_load.vinyl_path, vinyl_path, sizeof(args->snapshot_load.vinyl_path) );
     319             : 
     320           0 :   if( FD_UNLIKELY( strlen( vinyl_io )!=2UL ) ) FD_LOG_ERR(( "invalid --vinyl-io '%s'", vinyl_io ));
     321           0 :   fd_cstr_ncpy( args->snapshot_load.vinyl_io, vinyl_io, sizeof(args->snapshot_load.vinyl_io) );
     322           0 : }
     323             : 
     324             : static uint
     325             : fsck_funk( config_t * config,
     326           0 :            _Bool      lthash ) {
     327           0 :   ulong funk_obj_id = fd_pod_query_ulong( config->topo.props, "funk", ULONG_MAX );
     328           0 :   FD_TEST( funk_obj_id!=ULONG_MAX );
     329           0 :   void * funk_shmem = fd_topo_obj_laddr( &config->topo, funk_obj_id );
     330           0 :   fd_funk_t funk[1];
     331           0 :   FD_TEST( fd_funk_join( funk, funk_shmem ) );
     332           0 :   uint fsck_err = fd_accdb_fsck_funk( funk, lthash ? FD_ACCDB_FSCK_FLAGS_LTHASH : 0U );
     333           0 :   FD_TEST( fd_funk_leave( funk, NULL ) );
     334           0 :   return fsck_err;
     335           0 : }
     336             : 
     337             : static uint
     338             : fsck_vinyl( config_t * config,
     339           0 :            _Bool       lthash ) {
     340             :   /* Join meta index */
     341             : 
     342           0 :   fd_topo_t * topo = &config->topo;
     343           0 :   ulong meta_map_id  = fd_pod_query_ulong( topo->props, "vinyl.meta_map",  ULONG_MAX );
     344           0 :   ulong meta_pool_id = fd_pod_query_ulong( topo->props, "vinyl.meta_pool", ULONG_MAX );
     345           0 :   FD_TEST( meta_map_id!=ULONG_MAX && meta_pool_id!=ULONG_MAX );
     346           0 :   void * shmap = fd_topo_obj_laddr( topo, meta_map_id  );
     347           0 :   void * shele = fd_topo_obj_laddr( topo, meta_pool_id );
     348           0 :   fd_vinyl_meta_t meta[1];
     349           0 :   FD_TEST( fd_vinyl_meta_join( meta, shmap, shele ) );
     350             : 
     351             :   /* Join bstream */
     352             : 
     353           0 :   int dev_fd = open( config->paths.accounts, O_RDWR|O_CLOEXEC );
     354           0 :   if( FD_UNLIKELY( dev_fd<0 ) ) {
     355           0 :     FD_LOG_ERR(( "open(%s,O_RDWR|O_CLOEXEC) failed (%i-%s)",
     356           0 :                  config->paths.accounts, errno, fd_io_strerror( errno ) ));
     357           0 :   }
     358           0 :   void * mmio    = NULL;
     359           0 :   ulong  mmio_sz = 0UL;
     360           0 :   int map_err = fd_io_mmio_init( dev_fd, FD_IO_MMIO_MODE_READ_WRITE, &mmio, &mmio_sz );
     361           0 :   if( FD_UNLIKELY( map_err ) ) {
     362           0 :     FD_LOG_ERR(( "fd_io_mmio_init(%s,rw) failed (%i-%s)",
     363           0 :                  config->paths.accounts, map_err, fd_io_strerror( map_err ) ));
     364           0 :   }
     365           0 :   FD_TEST( 0==close( dev_fd ) );
     366           0 :   ulong  io_spad_max = 1UL<<20;
     367           0 :   void * io_mm       = aligned_alloc( fd_vinyl_io_mm_align(), fd_vinyl_io_mm_footprint( io_spad_max ) );
     368           0 :   FD_TEST( io_mm );
     369           0 :   fd_vinyl_io_t * io = fd_vinyl_io_mm_init( io_mm, io_spad_max, mmio, mmio_sz, 0, NULL, 0UL, 0UL );
     370           0 :   FD_TEST( io );
     371             : 
     372             :   /* Run verifier */
     373             : 
     374           0 :   uint fsck_err = fd_accdb_fsck_vinyl( io, meta, lthash ? FD_ACCDB_FSCK_FLAGS_LTHASH : 0U );
     375             : 
     376             :   /* Clean up */
     377             : 
     378           0 :   FD_TEST( fd_vinyl_io_fini( io ) );
     379           0 :   free( io_mm );
     380           0 :   fd_io_mmio_fini( mmio, mmio_sz );
     381           0 :   fd_vinyl_meta_leave( meta );
     382           0 :   return fsck_err;
     383           0 : }
     384             : 
     385             : /* ACCOUNTS_HIST_N (32) is chosen to make the histogram lightweight.
     386             :    And because accounts can have a data size in the range [0, 10MiB],
     387             :    the width of the bins increments in powers of 2.  In the future, it
     388             :    should be possible to pass this as a configuration parameter. */
     389           0 : #define ACCOUNTS_HIST_N (32)
     390             : 
     391             : struct accounts_hist {
     392             :   ulong total_cnt;
     393             :   ulong total_acc;
     394             :   ulong bin_thi[ ACCOUNTS_HIST_N ];
     395             :   ulong bin_cnt[ ACCOUNTS_HIST_N ];
     396             :   ulong bin_acc[ ACCOUNTS_HIST_N ];
     397             :   ulong bin_min[ ACCOUNTS_HIST_N ];
     398             :   ulong bin_max[ ACCOUNTS_HIST_N ];
     399             :   ulong token_cnt;
     400             : };
     401             : typedef struct accounts_hist accounts_hist_t;
     402             : 
     403             : static inline void
     404           0 : accounts_hist_reset( accounts_hist_t * hist ) {
     405           0 :   hist->total_cnt = 0UL;
     406           0 :   hist->total_acc = 0UL;
     407           0 :   for( int i=0; i < ACCOUNTS_HIST_N; i++ ) {
     408           0 :     hist->bin_thi[ i ] = fd_ulong_if( i > 0, fd_pow2( ulong, i-1 ), 0UL );
     409           0 :     hist->bin_cnt[ i ] = 0UL;
     410           0 :     hist->bin_acc[ i ] = 0UL;
     411           0 :     hist->bin_min[ i ] = ULONG_MAX;
     412           0 :     hist->bin_max[ i ] = 0UL;
     413           0 :   }
     414           0 :   hist->token_cnt = 0UL;
     415           0 : }
     416             : 
     417             : static inline void
     418             : accounts_hist_update( accounts_hist_t * hist,
     419           0 :                       ulong             account_sz ) {
     420           0 :   hist->total_cnt += 1UL;
     421           0 :   hist->total_acc += account_sz;
     422           0 :   int i=0;
     423             :   /* This allows for arbitrary thresholds - not optimized for pow2
     424             :      bins. */
     425           0 :   for( ; i < ACCOUNTS_HIST_N; i++ ) {
     426           0 :     if( FD_UNLIKELY( account_sz <= hist->bin_thi[ i ] )) {
     427           0 :       hist->bin_cnt[ i ] += 1;
     428           0 :       hist->bin_acc[ i ] += account_sz;
     429           0 :       hist->bin_min[ i ] = fd_ulong_min( hist->bin_min[ i ], account_sz );
     430           0 :       hist->bin_max[ i ] = fd_ulong_max( hist->bin_max[ i ], account_sz );
     431           0 :       break;
     432           0 :     }
     433           0 :   }
     434           0 :   FD_TEST( i < ACCOUNTS_HIST_N );
     435           0 : }
     436             : 
     437             : static inline int
     438           0 : accounts_hist_check( accounts_hist_t const * hist ) {
     439           0 :   ulong cnt = 0UL;
     440           0 :   ulong acc = 0UL;
     441           0 :   for( int i=0; i < ACCOUNTS_HIST_N; i++ ) {
     442           0 :     cnt += hist->bin_cnt[ i ];
     443           0 :     acc += hist->bin_acc[ i ];
     444           0 :   }
     445           0 :   if( cnt != hist->total_cnt ) return -1;
     446           0 :   if( acc != hist->total_acc ) return -2;
     447           0 :   return 0;
     448           0 : }
     449             : 
     450             : static void
     451           0 : accounts_hist_print( accounts_hist_t const * hist ) {
     452           0 :   double hist_total_cnt_M   = (double)hist->total_cnt / (double)1.0e6;
     453           0 :   double hist_total_cnt_GiB = (double)hist->total_acc / (double)1073741824;
     454           0 :   printf( "\n" );
     455           0 :   printf( "hist_total_cnt %16lu ( %6.1f M   )\n", hist->total_cnt, hist_total_cnt_M   );
     456           0 :   printf( "hist_total_acc %16lu ( %6.1f GiB )\n", hist->total_acc, hist_total_cnt_GiB );
     457           0 :   printf( "   bin_th_lo <  sz <=    bin_th_hi |    bin_cnt (run_sum%%) |      bin_acc (run_sum%%) |    bin_min B |    bin_max B |    bin_avg B |\n" );
     458           0 :   ulong sum_cnt = 0UL;
     459           0 :   ulong sum_acc = 0UL;
     460           0 :   for( int i=0; i < ACCOUNTS_HIST_N; i++ ) {
     461             :     /* bin thresholds */
     462           0 :     ulong hist_bin_tlo      = hist->bin_thi[ fd_int_if( i>0, i-1, i ) ];
     463           0 :     ulong hist_bin_thi      = hist->bin_thi[ i ];
     464             :     /* bin cnt */
     465           0 :     ulong hist_bin_cnt      = hist->bin_cnt[ i ];
     466           0 :     sum_cnt                += hist->bin_cnt[ i ];
     467           0 :     double sum_cnt_p        = (double)(sum_cnt * 100) / (double)hist->total_cnt;
     468           0 :     double hist_bin_cnt_K   = (double)(hist_bin_cnt) / (double)1.0e3;
     469             :     /* bin acc */
     470           0 :     ulong hist_bin_acc      = hist->bin_acc[ i ];
     471           0 :     sum_acc                += hist->bin_acc[ i ];
     472           0 :     double sum_acc_p        = (double)(sum_acc * 100) / (double)hist->total_acc;
     473           0 :     double hist_bin_acc_MiB = (double)(hist_bin_acc) / (double)1048576.0f;
     474             :     /* bin min, max, avg */
     475           0 :     ulong hist_bin_min      = fd_ulong_if( hist->bin_cnt[ i ] > 0, hist->bin_min[ i ], 0UL );
     476           0 :     ulong hist_bin_max      = hist->bin_max[ i ];
     477           0 :     ulong hist_bin_avg      = fd_ulong_if( hist->bin_cnt[ i ] > 0, hist->bin_acc[ i ] / hist->bin_cnt[ i ], 0UL );
     478             :     /* log */
     479           0 :     char buf[256];
     480           0 :     char * p = fd_cstr_init( buf );
     481           0 :     p = fd_cstr_append_printf( p, "%12lu %s sz <= %12lu |", hist_bin_tlo, i==0? "<=" : "< ", hist_bin_thi );
     482           0 :     p = fd_cstr_append_printf( p, " %8.1f K (%6.1f %%) |", hist_bin_cnt_K, sum_cnt_p );
     483           0 :     p = fd_cstr_append_printf( p, " %8.1f MiB (%6.1f %%) |", hist_bin_acc_MiB, sum_acc_p );
     484           0 :     p = fd_cstr_append_printf( p, " %12lu | %12lu | %12lu |", hist_bin_min, hist_bin_max, hist_bin_avg );
     485           0 :     p = fd_cstr_append_printf( p, "\n" );
     486           0 :     printf( "%s", buf );
     487           0 :   }
     488           0 :   printf( "\n" );
     489           0 : }
     490             : 
     491             : static void
     492             : accounts_hist_vinyl( accounts_hist_t * hist,
     493           0 :                      config_t *        config ) {
     494           0 :   fd_topo_t * topo = &config->topo;
     495           0 :   ulong meta_map_id  = fd_pod_query_ulong( topo->props, "vinyl.meta_map",  ULONG_MAX );
     496           0 :   ulong meta_pool_id = fd_pod_query_ulong( topo->props, "vinyl.meta_pool", ULONG_MAX );
     497           0 :   FD_TEST( meta_map_id!=ULONG_MAX && meta_pool_id!=ULONG_MAX );
     498           0 :   void * shmap = fd_topo_obj_laddr( topo, meta_map_id  );
     499           0 :   void * shele = fd_topo_obj_laddr( topo, meta_pool_id );
     500           0 :   fd_vinyl_meta_t meta[1];
     501           0 :   FD_TEST( fd_vinyl_meta_join( meta, shmap, shele ) );
     502             : 
     503           0 :   for( ulong ele_i=0; ele_i < fd_vinyl_meta_ele_max( meta ); ele_i++ ) {
     504           0 :     fd_vinyl_meta_ele_t const * ele = meta->ele + ele_i;
     505           0 :     if( FD_UNLIKELY( fd_vinyl_meta_private_ele_is_free( meta->ctx, ele ) ) ) continue;
     506           0 :     accounts_hist_update( hist, (ulong)ele->phdr.info.val_sz );
     507           0 :   }
     508           0 : }
     509             : 
     510             : static void
     511             : accounts_hist_funk( accounts_hist_t * hist,
     512           0 :                     config_t *        config ) {
     513           0 :   fd_topo_t * topo = &config->topo;
     514           0 :   ulong funk_obj_id = fd_pod_query_ulong( topo->props, "funk", ULONG_MAX );
     515           0 :   FD_TEST( funk_obj_id!=ULONG_MAX );
     516           0 :   void * funk_shmem = fd_topo_obj_laddr( topo, funk_obj_id );
     517           0 :   fd_funk_t funk[1];
     518           0 :   FD_TEST( fd_funk_join( funk, funk_shmem ) );
     519             : 
     520           0 :   fd_funk_rec_map_t const * rec_map = funk->rec_map;
     521           0 :   fd_funk_rec_t const * ele = rec_map->ele;
     522           0 :   fd_funk_rec_map_shmem_private_chain_t const * chain = fd_funk_rec_map_shmem_private_chain_const( rec_map->map, 0UL );
     523           0 :   ulong chain_cnt = fd_funk_rec_map_chain_cnt( rec_map );
     524           0 :   for( ulong chain_i=0UL; chain_i < chain_cnt; chain_i++ ) {
     525           0 :     ulong ver_cnt = chain[ chain_i ].ver_cnt;
     526           0 :     ulong ele_cnt = fd_funk_rec_map_private_vcnt_cnt( ver_cnt );
     527           0 :     ulong head_i  = fd_funk_rec_map_private_idx( chain[ chain_i ].head_cidx );
     528           0 :     ulong ele_i   = head_i;
     529           0 :     for( ulong ele_rem=ele_cnt; ele_rem; ele_rem-- ) {
     530           0 :       fd_funk_xid_key_pair_t const * pair = &ele[ ele_i ].pair;
     531           0 :       fd_funk_rec_query_t query[1];
     532           0 :       fd_funk_rec_t * rec = fd_funk_rec_query_try( funk, pair->xid, pair->key, query );
     533           0 :       FD_TEST( !!rec );
     534           0 :       fd_account_meta_t * meta = fd_funk_val( rec, funk->wksp );
     535           0 :       FD_TEST( !!meta );
     536           0 :       accounts_hist_update( hist, sizeof(fd_account_meta_t) + meta->dlen );
     537           0 :     }
     538           0 :   }
     539           0 : }
     540             : 
     541             : /* fixup_config applies command-line arguments to config, overriding
     542             :    defaults / config file */
     543             : 
     544             : static void
     545             : fixup_config( config_t *     config,
     546           0 :               args_t const * args ) {
     547           0 :   fd_topo_t * topo = &config->topo;
     548           0 :   if( args->snapshot_load.snapshot_dir[0] ) {
     549           0 :     fd_cstr_ncpy( config->paths.snapshots, args->snapshot_load.snapshot_dir, sizeof(config->paths.snapshots) );
     550           0 :   }
     551             : 
     552           0 :   if( args->snapshot_load.vinyl_path[0] ) {
     553           0 :     fd_cstr_ncpy( config->paths.accounts, args->snapshot_load.vinyl_path, sizeof(config->paths.accounts) );
     554           0 :   }
     555             : 
     556           0 :   if( args->snapshot_load.db_rec_max ) {
     557           0 :     config->firedancer.funk.max_account_records = args->snapshot_load.db_rec_max;
     558           0 :   }
     559             : 
     560           0 :   if( args->snapshot_load.db_sz ) {
     561           0 :     config->firedancer.funk.heap_size_gib = fd_ulong_align_up( args->snapshot_load.db_sz, (1UL<<30) )>>30;
     562           0 :   }
     563             : 
     564           0 :   if( args->snapshot_load.cache_sz ) {
     565           0 :     config->firedancer.vinyl.cache_size_gib = fd_ulong_align_up( args->snapshot_load.cache_sz, (1UL<<30) )>>30;
     566           0 :   }
     567             : 
     568           0 :   if( args->snapshot_load.cache_rec_max ) {
     569           0 :     config->firedancer.vinyl.max_cache_entries = args->snapshot_load.cache_rec_max;
     570           0 :   }
     571             : 
     572           0 :   if( args->snapshot_load.is_vinyl ) {
     573           0 :     config->firedancer.vinyl.enabled = 1;
     574             : 
     575           0 :     config->firedancer.vinyl.file_size_gib       = config->firedancer.funk.heap_size_gib;
     576           0 :     config->firedancer.vinyl.max_account_records = config->firedancer.funk.max_account_records;
     577             : 
     578           0 :     config->firedancer.funk.heap_size_gib       = 0;
     579           0 :     config->firedancer.funk.max_account_records = 0;
     580             : 
     581           0 :     char const * io_mode = args->snapshot_load.vinyl_io;
     582           0 :     if(      0==strcmp( io_mode, "ur" ) ) config->firedancer.vinyl.io_uring.enabled = 1;
     583           0 :     else if( 0==strcmp( io_mode, "bd" ) ) {}
     584           0 :     else FD_LOG_ERR(( "unsupported --vinyl-io '%s' (valid options are 'bd' and 'ur')", io_mode ));
     585           0 :   }
     586             : 
     587           0 :   if( args->snapshot_load.offline ) {
     588           0 :     config->firedancer.snapshots.sources.gossip.allow_any      = 0;
     589           0 :     config->firedancer.snapshots.sources.gossip.allow_list_cnt = 0;
     590           0 :     config->firedancer.snapshots.sources.servers_cnt           = 0;
     591           0 :   }
     592             : 
     593           0 :   if( args->snapshot_load.no_incremental ) {
     594           0 :     config->firedancer.snapshots.incremental_snapshots = 0;
     595           0 :   }
     596             : 
     597           0 :   config->development.snapshots.disable_lthash_verification = !args->snapshot_load.lthash;
     598             : 
     599             :   /* FIXME Unfortunately, the fdctl boot procedure constructs the
     600             :            topology before parsing command-line arguments.  So, here,
     601             :            we construct the topology again (a third time ... sigh). */
     602           0 :   snapshot_load_topo( config, args->snapshot_load.vinyl_server );
     603             : 
     604           0 :   fd_topob_auto_layout( topo, 0 );
     605           0 :   fd_topob_finish( topo, CALLBACKS );
     606           0 : }
     607             : 
     608             : static void
     609             : snapshot_load_cmd_fn( args_t *   args,
     610           0 :                       config_t * config ) {
     611           0 :   fixup_config( config, args );
     612           0 :   if( FD_UNLIKELY( config->firedancer.snapshots.sources.gossip.allow_any || 0UL!=config->firedancer.snapshots.sources.gossip.allow_list_cnt ) ) {
     613           0 :     FD_LOG_ERR(( "snapshot-load command is incompatible with gossip snapshot sources" ));
     614           0 :   }
     615           0 :   _Bool watch = !args->snapshot_load.no_watch;
     616             : 
     617           0 :   fd_topo_t * topo = &config->topo;
     618             : 
     619           0 :   args_t configure_args = {
     620           0 :     .configure.command = CONFIGURE_CMD_INIT,
     621           0 :   };
     622             : 
     623           0 :   for( ulong i=0UL; STAGES[ i ]; i++ )
     624           0 :     configure_args.configure.stages[ i ] = STAGES[ i ];
     625           0 :   configure_cmd_fn( &configure_args, config );
     626             : 
     627           0 :   run_firedancer_init( config, 1, 0 );
     628             : 
     629           0 :   fd_log_private_shared_lock[ 1 ] = 0;
     630           0 :   fd_topo_join_workspaces( topo, FD_SHMEM_JOIN_MODE_READ_WRITE );
     631           0 :   fd_topo_fill( topo );
     632             : 
     633           0 :   fd_topo_tile_t * snapct_tile = &topo->tiles[ fd_topo_find_tile( topo, "snapct", 0UL ) ];
     634           0 :   fd_topo_tile_t * snapld_tile = &topo->tiles[ fd_topo_find_tile( topo, "snapld", 0UL ) ];
     635           0 :   fd_topo_tile_t * snapdc_tile = &topo->tiles[ fd_topo_find_tile( topo, "snapdc", 0UL ) ];
     636           0 :   fd_topo_tile_t * snapin_tile = &topo->tiles[ fd_topo_find_tile( topo, "snapin", 0UL ) ];
     637           0 :   ulong            snapwh_idx  =               fd_topo_find_tile( topo, "snapwh", 0UL );
     638           0 :   ulong            snapwr_idx  =               fd_topo_find_tile( topo, "snapwr", 0UL );
     639           0 :   fd_topo_tile_t * snapwh_tile = snapwh_idx!=ULONG_MAX ? &topo->tiles[ snapwh_idx ] : NULL;
     640           0 :   fd_topo_tile_t * snapwr_tile = snapwr_idx!=ULONG_MAX ? &topo->tiles[ snapwr_idx ] : NULL;
     641           0 :   ulong            snapla_idx  =               fd_topo_find_tile( topo, "snapla", 0UL );
     642           0 :   fd_topo_tile_t * snapla_tile = snapla_idx!=ULONG_MAX ? &topo->tiles[ snapla_idx ] : NULL;
     643           0 :   ulong            snapls_idx  =               fd_topo_find_tile( topo, "snapls", 0UL );
     644           0 :   fd_topo_tile_t * snapls_tile = snapls_idx!=ULONG_MAX ? &topo->tiles[ snapls_idx ] : NULL;
     645             : 
     646           0 :   double tick_per_ns = fd_tempo_tick_per_ns( NULL );
     647           0 :   double ns_per_tick = 1.0/tick_per_ns;
     648             : 
     649           0 :   long start = fd_log_wallclock();
     650           0 :   fd_topo_run_single_process( topo, 2, config->uid, config->gid, fdctl_tile_run );
     651             : 
     652           0 :   ulong volatile * const snapct_metrics = fd_metrics_tile( snapct_tile->metrics );
     653           0 :   ulong volatile * const snapld_metrics = fd_metrics_tile( snapld_tile->metrics );
     654           0 :   ulong volatile * const snapdc_metrics = fd_metrics_tile( snapdc_tile->metrics );
     655           0 :   ulong volatile * const snapin_metrics = fd_metrics_tile( snapin_tile->metrics );
     656           0 :   ulong volatile * const snapwh_metrics = snapwh_tile ? fd_metrics_tile( snapwh_tile->metrics ) : NULL;
     657           0 :   ulong volatile * const snapwr_metrics = snapwr_tile ? fd_metrics_tile( snapwr_tile->metrics ) : NULL;
     658           0 :   ulong volatile * const snapla_metrics = snapla_tile ? fd_metrics_tile( snapla_tile->metrics ) : NULL;
     659           0 :   ulong volatile * const snapls_metrics = snapls_tile ? fd_metrics_tile( snapls_tile->metrics ) : NULL;
     660             : 
     661           0 :   ulong total_off_old    = 0UL;
     662           0 :   ulong decomp_off_old   = 0UL;
     663           0 :   ulong vinyl_off_old    = 0UL;
     664           0 :   ulong snapld_backp_old = 0UL;
     665           0 :   ulong snapld_wait_old  = 0UL;
     666           0 :   ulong snapdc_backp_old = 0UL;
     667           0 :   ulong snapdc_wait_old  = 0UL;
     668           0 :   ulong snapin_backp_old = 0UL;
     669           0 :   ulong snapin_wait_old  = 0UL;
     670           0 :   ulong snapwh_wait_old  = 0UL;
     671           0 :   ulong snapwr_wait_old  = 0UL;
     672           0 :   ulong snapla_backp_old = 0UL;
     673           0 :   ulong snapla_wait_old  = 0UL;
     674           0 :   ulong snapls_backp_old = 0UL;
     675           0 :   ulong snapls_wait_old  = 0UL;
     676           0 :   ulong acc_cnt_old      = 0UL;
     677             : 
     678           0 :   sleep( 1 );
     679           0 :   if( watch ) {
     680           0 :     puts( "" );
     681           0 :     puts( "Columns:" );
     682           0 :     puts( "- comp:  Compressed bandwidth"             );
     683           0 :     puts( "- raw:   Uncompressed bandwidth"           );
     684           0 :     puts( "- backp: Backpressured by downstream tile" );
     685           0 :     puts( "- stall: Waiting on upstream tile"         );
     686           0 :     puts( "- acc:   Number of accounts"               );
     687           0 :     puts( "" );
     688           0 :     fputs( "--------------------------------------------", stdout );
     689           0 :     if( snapwr_tile ) fputs( "--------------", stdout );
     690           0 :     if( snapls_tile ) fputs( "[ld],[dc],[in],[la],[ls]--------[ld],[dc],[in],[la],[ls]", stdout );
     691           0 :     else              fputs( "[ld],[dc],[in]--------[ld],[dc],[in]", stdout );
     692           0 :     if( snapwr_tile ) fputs( ",[wh],[wr]" , stdout );
     693           0 :     puts( "--------------" );
     694           0 :   }
     695             : 
     696           0 :   long next = start+1000L*1000L*1000L;
     697           0 :   for(;;) {
     698           0 :     ulong snapct_status = FD_VOLATILE_CONST( snapct_metrics[ MIDX( GAUGE, TILE, STATUS ) ] );
     699           0 :     ulong snapld_status = FD_VOLATILE_CONST( snapld_metrics[ MIDX( GAUGE, TILE, STATUS ) ] );
     700           0 :     ulong snapdc_status = FD_VOLATILE_CONST( snapdc_metrics[ MIDX( GAUGE, TILE, STATUS ) ] );
     701           0 :     ulong snapin_status = FD_VOLATILE_CONST( snapin_metrics[ MIDX( GAUGE, TILE, STATUS ) ] );
     702           0 :     ulong snapls_status = snapls_metrics ? FD_VOLATILE_CONST( snapls_metrics[ MIDX( GAUGE, TILE, STATUS ) ] ) : 2UL;
     703             : 
     704           0 :     if( FD_UNLIKELY( snapct_status==2UL && snapld_status==2UL && snapdc_status==2UL && snapin_status==2UL && snapls_status==2UL ) ) break;
     705             : 
     706           0 :     long cur = fd_log_wallclock();
     707           0 :     if( FD_UNLIKELY( cur<next ) ) {
     708           0 :       long sleep_nanos = fd_long_min( 1000L*1000L, next-cur );
     709           0 :       FD_TEST( !fd_sys_util_nanosleep(  (uint)(sleep_nanos/(1000L*1000L*1000L)), (uint)(sleep_nanos%(1000L*1000L*1000L)) ) );
     710           0 :       continue;
     711           0 :     }
     712             : 
     713           0 :     ulong total_off    = snapct_metrics[ MIDX( GAUGE, SNAPCT, FULL_BYTES_READ ) ] +
     714           0 :                          snapct_metrics[ MIDX( GAUGE, SNAPCT, INCREMENTAL_BYTES_READ ) ];
     715           0 :     ulong decomp_off   = snapdc_metrics[ MIDX( GAUGE, SNAPDC, FULL_DECOMPRESSED_BYTES_WRITTEN ) ] +
     716           0 :                          snapdc_metrics[ MIDX( GAUGE, SNAPDC, INCREMENTAL_DECOMPRESSED_BYTES_WRITTEN ) ];
     717           0 :     ulong vinyl_off    = snapwr_tile ? snapwr_metrics[ MIDX( GAUGE, SNAPWR, VINYL_BYTES_WRITTEN ) ] : 0UL;
     718           0 :     ulong snapld_backp = snapld_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_PREFRAG ) ];
     719           0 :     ulong snapld_wait  = snapld_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_POSTFRAG   ) ] + snapld_backp;
     720           0 :     ulong snapdc_backp = snapdc_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_PREFRAG ) ];
     721           0 :     ulong snapdc_wait  = snapdc_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_POSTFRAG   ) ] + snapdc_backp;
     722           0 :     ulong snapin_backp = snapin_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_PREFRAG ) ];
     723           0 :     ulong snapin_wait  = snapin_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_POSTFRAG   ) ] + snapin_backp;
     724           0 :     ulong snapwh_wait  = 0UL;
     725           0 :     ulong snapwr_wait  = 0UL;
     726           0 :     ulong snapla_backp = snapla_metrics ? snapla_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_PREFRAG ) ] : 0UL;
     727           0 :     ulong snapla_wait  = snapla_metrics ? snapla_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_POSTFRAG   ) ] + snapla_backp : 0UL;
     728           0 :     ulong snapls_backp = snapls_metrics ? snapls_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_PREFRAG ) ] : 0UL;
     729           0 :     ulong snapls_wait  = snapls_metrics ? snapls_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_POSTFRAG   ) ] + snapls_backp : 0UL;
     730           0 :     if( snapwr_tile ) {
     731           0 :       snapwh_wait      = snapwh_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_POSTFRAG   ) ] +
     732           0 :                          snapwh_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_PREFRAG ) ];
     733           0 :       snapwr_wait      = snapwr_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_CAUGHT_UP_POSTFRAG   ) ] +
     734           0 :                          snapwr_metrics[ MIDX( COUNTER, TILE, REGIME_DURATION_NANOS_BACKPRESSURE_PREFRAG ) ];
     735           0 :     }
     736             : 
     737           0 :     double progress = 100.0 * (double)snapct_metrics[ MIDX( GAUGE, SNAPCT, FULL_BYTES_READ ) ] / (double)snapct_metrics[ MIDX( GAUGE, SNAPCT, FULL_BYTES_TOTAL ) ];
     738             : 
     739           0 :     ulong acc_cnt      = snapin_metrics[ MIDX( GAUGE, SNAPIN, ACCOUNTS_INSERTED    ) ];
     740             : 
     741           0 :     if( watch ) {
     742           0 :       printf( "%5.1f %% comp=%4.0fMB/s snap=%4.0fMB/s",
     743           0 :               progress,
     744           0 :               (double)( total_off -total_off_old  )/1e6,
     745           0 :               (double)( decomp_off-decomp_off_old )/1e6 );
     746           0 :       if( snapwr_tile ) {
     747           0 :         printf( " vinyl=%4.0fMB/s", (double)( vinyl_off - vinyl_off_old )/1e6 );
     748           0 :       }
     749           0 :       if( !snapls_tile )  {
     750           0 :         printf( " backp=(%3.0f%%,%3.0f%%,%3.0f%%",
     751           0 :           ( (double)( snapld_backp-snapld_backp_old )*ns_per_tick )/1e7,
     752           0 :           ( (double)( snapdc_backp-snapdc_backp_old )*ns_per_tick )/1e7,
     753           0 :           ( (double)( snapin_backp-snapin_backp_old )*ns_per_tick )/1e7 );
     754           0 :       }
     755           0 :       else {
     756           0 :         printf( " backp=(%3.0f%%,%3.0f%%,%3.0f%%,%3.0f%%,%3.0f%%",
     757           0 :           ( (double)( snapld_backp-snapld_backp_old )*ns_per_tick )/1e7,
     758           0 :           ( (double)( snapdc_backp-snapdc_backp_old )*ns_per_tick )/1e7,
     759           0 :           ( (double)( snapin_backp-snapin_backp_old )*ns_per_tick )/1e7,
     760           0 :           ( (double)( snapla_backp-snapla_backp_old )*ns_per_tick )/1e7,
     761           0 :           ( (double)( snapls_backp-snapls_backp_old )*ns_per_tick )/1e7 );
     762           0 :       }
     763           0 :       if( !snapls_tile ) {
     764           0 :         printf( ") busy=(%3.0f%%,%3.0f%%,%3.0f%%",
     765           0 :           100-( ( (double)( snapld_wait-snapld_wait_old  )*ns_per_tick )/1e7 ),
     766           0 :           100-( ( (double)( snapdc_wait-snapdc_wait_old  )*ns_per_tick )/1e7 ),
     767           0 :           100-( ( (double)( snapin_wait-snapin_wait_old  )*ns_per_tick )/1e7 ) );
     768           0 :       } else {
     769           0 :         printf( ") busy=(%3.0f%%,%3.0f%%,%3.0f%%,%3.0f%%,%3.0f%%",
     770           0 :           100-( ( (double)( snapld_wait-snapld_wait_old  )*ns_per_tick )/1e7 ),
     771           0 :           100-( ( (double)( snapdc_wait-snapdc_wait_old  )*ns_per_tick )/1e7 ),
     772           0 :           100-( ( (double)( snapin_wait-snapin_wait_old  )*ns_per_tick )/1e7 ),
     773           0 :           100-( ( (double)( snapla_wait-snapla_wait_old  )*ns_per_tick )/1e7 ),
     774           0 :           100-( ( (double)( snapls_wait-snapls_wait_old  )*ns_per_tick )/1e7 ) );
     775           0 :       }
     776           0 :       if( snapwr_tile ) {
     777           0 :         printf( ",%3.0f%%,%3.0f%%",
     778           0 :               100-( ( (double)( snapwh_wait-snapwh_wait_old  )*ns_per_tick )/1e7 ),
     779           0 :               100-( ( (double)( snapwr_wait-snapwr_wait_old  )*ns_per_tick )/1e7 ) );
     780           0 :       }
     781           0 :       printf( ") acc=%4.1f M/s\n",
     782           0 :               (double)( acc_cnt-acc_cnt_old  )/1e6 );
     783           0 :       fflush( stdout );
     784           0 :     }
     785           0 :     total_off_old    = total_off;
     786           0 :     decomp_off_old   = decomp_off;
     787           0 :     vinyl_off_old    = vinyl_off;
     788           0 :     snapld_backp_old = snapld_backp;
     789           0 :     snapld_wait_old  = snapld_wait;
     790           0 :     snapdc_backp_old = snapdc_backp;
     791           0 :     snapdc_wait_old  = snapdc_wait;
     792           0 :     snapin_backp_old = snapin_backp;
     793           0 :     snapin_wait_old  = snapin_wait;
     794           0 :     snapwh_wait_old  = snapwh_wait;
     795           0 :     snapwr_wait_old  = snapwr_wait;
     796           0 :     snapla_backp_old = snapla_backp;
     797           0 :     snapla_wait_old  = snapla_wait;
     798           0 :     snapls_backp_old = snapls_backp;
     799           0 :     snapls_wait_old  = snapls_wait;
     800           0 :     acc_cnt_old      = acc_cnt;
     801             : 
     802           0 :     next+=1000L*1000L*1000L;
     803           0 :   }
     804             : 
     805           0 :   if( args->snapshot_load.fsck ) {
     806           0 :     FD_LOG_NOTICE(( "FSCK: starting" ));
     807           0 :     uint fsck_err;
     808           0 :     if( snapwr_tile ) fsck_err = fsck_vinyl( config, args->snapshot_load.fsck_lthash );
     809           0 :     else              fsck_err = fsck_funk ( config, args->snapshot_load.fsck_lthash );
     810           0 :     if( !fsck_err ) {
     811           0 :       FD_LOG_NOTICE(( "FSCK: passed" ));
     812           0 :     } else {
     813           0 :       FD_LOG_ERR(( "FSCK: errors detected" ));
     814           0 :     }
     815           0 :   }
     816             : 
     817           0 :   if( args->snapshot_load.accounts_hist ) {
     818           0 :     accounts_hist_t hist[1];
     819           0 :     accounts_hist_reset( hist );
     820           0 :     FD_LOG_NOTICE(( "Accounts histogram: starting" ));
     821           0 :     if( snapwr_tile ) accounts_hist_vinyl( hist, config );
     822           0 :     else              accounts_hist_funk ( hist, config );
     823           0 :     FD_TEST( !accounts_hist_check( hist ) );
     824           0 :     accounts_hist_print( hist );
     825           0 :   }
     826             : 
     827           0 :   if( args->snapshot_load.vinyl_server ) {
     828             :     /* Generate a config pod */
     829           0 :     fd_wksp_t * server_wksp = topo->workspaces[ fd_topo_find_wksp( topo, "vinyl_server" ) ].wksp;
     830           0 :     ulong const cfg_pod_sz = 8192UL;
     831           0 :     ulong cfg_gaddr = fd_wksp_alloc( server_wksp, fd_pod_align(), fd_pod_footprint( cfg_pod_sz ), 1UL );
     832           0 :     FD_TEST( cfg_gaddr );
     833           0 :     uchar * cfg = fd_pod_join( fd_pod_new( fd_wksp_laddr( server_wksp, cfg_gaddr ), cfg_pod_sz ) );
     834           0 :     FD_TEST( cfg );
     835           0 :     char gaddr_tmp[ 256 ];
     836           0 : #   define POD_ADD( key, obj_id ) do {                                 \
     837           0 :       ulong _obj_id = (obj_id);                                        \
     838           0 :       FD_TEST( _obj_id!=ULONG_MAX );                                   \
     839           0 :       fd_topo_obj_t * _obj = &topo->objs[ _obj_id ];                   \
     840           0 :       FD_TEST( fd_cstr_printf_check( gaddr_tmp, sizeof(gaddr_tmp), NULL, "%s_%s.wksp:%lu", topo->app_name, topo->workspaces[ _obj->wksp_id ].name, _obj->offset ) ); \
     841           0 :       FD_TEST( fd_pod_insert_cstr( cfg, (key), gaddr_tmp )!=0UL );     \
     842           0 :     } while(0)
     843           0 :     POD_ADD( "cnc",  fd_pod_query_ulong( topo->props, "vinyl.cnc",       ULONG_MAX ) );
     844           0 :     POD_ADD( "meta", fd_pod_query_ulong( topo->props, "vinyl.meta_map",  ULONG_MAX ) );
     845           0 :     POD_ADD( "ele",  fd_pod_query_ulong( topo->props, "vinyl.meta_pool", ULONG_MAX ) );
     846           0 :     POD_ADD( "obj",  fd_pod_query_ulong( topo->props, "vinyl.data",      ULONG_MAX ) );
     847           0 : #   undef POD_ADD
     848           0 :     fd_pod_leave( cfg );
     849           0 :     FD_LOG_NOTICE(( "Wrote vinyl topology pod to %s_%s.wksp:%lu", topo->app_name, "vinyl_server", cfg_gaddr ));
     850             : 
     851             :     /* Wait for vinyl tile to boot */
     852           0 :     fd_cnc_t * cnc = fd_cnc_join( fd_topo_obj_laddr( topo, fd_pod_query_ulong( topo->props, "vinyl.cnc", ULONG_MAX )  ) );
     853           0 :     FD_TEST( cnc );
     854           0 :     ulong vinyl_status = fd_cnc_wait( cnc, FD_VINYL_CNC_SIGNAL_BOOT, LONG_MAX, NULL );
     855           0 :     FD_TEST( vinyl_status==FD_VINYL_CNC_SIGNAL_RUN );
     856           0 :     FD_LOG_NOTICE(( "Vinyl server running" ));
     857           0 :     for(;;) {
     858           0 :       vinyl_status = fd_cnc_wait( cnc, vinyl_status, LONG_MAX, NULL );
     859           0 :       char cnc_signal_cstr[ FD_VINYL_CNC_SIGNAL_CSTR_BUF_MAX ];
     860           0 :       fd_vinyl_cnc_signal_cstr( vinyl_status, cnc_signal_cstr );
     861           0 :       FD_LOG_NOTICE(( "Vinyl CNC signal %s", cnc_signal_cstr ));
     862             :       //if( vinyl_status==FD_VINYL_CNC_SIGNAL_BOOT ) break;
     863           0 :     }
     864           0 :     FD_LOG_NOTICE(( "Vinyl server shut down" ));
     865           0 :     fd_cnc_leave( cnc );
     866           0 :   }
     867           0 : }
     868             : 
     869             : action_t fd_action_snapshot_load = {
     870             :   .name = NAME,
     871             :   .topo = snapshot_load_topo1,
     872             :   .perm = dev_cmd_perm,
     873             :   .args = snapshot_load_args,
     874             :   .fn   = snapshot_load_cmd_fn
     875             : };

Generated by: LCOV version 1.14