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

Generated by: LCOV version 1.14