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 : };
|