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