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