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