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