Line data Source code
1 : /* The 'vinyl' tile is a thin wrapper over 'fd_vinyl_exec'.
2 :
3 : This tile sleeps (using stem) until the system boots initial chain
4 : state (from snapshot or genesis). Then, fd_vinyl_exec hijacks the
5 : stem run loop and takes over. */
6 :
7 : #include "../../disco/topo/fd_topo.h"
8 : #include "../../discof/restore/utils/fd_ssmsg.h"
9 : #include "../../vinyl/fd_vinyl.h"
10 : #include "../../vinyl/io/fd_vinyl_io_ur.h"
11 :
12 : #include <errno.h>
13 : #include <fcntl.h>
14 : #if FD_HAS_LIBURING
15 : #include <liburing.h>
16 : #endif
17 :
18 : #define NAME "vinyl"
19 : #define MAX_INS 8
20 :
21 0 : #define IN_KIND_GENESIS 1
22 0 : #define IN_KIND_SNAP 2
23 :
24 0 : #define IO_SPAD_MAX (32UL<<20)
25 :
26 : struct fd_vinyl_tile_ctx {
27 : fd_vinyl_t * vinyl;
28 : uint in_kind[ MAX_INS ];
29 : int bstream_fd;
30 :
31 : void * io_mem;
32 : void * vinyl_mem;
33 : void * line_mem; ulong line_footprint;
34 : void * cnc_mem; ulong cnc_footprint;
35 : void * meta_mem; ulong meta_footprint;
36 : void * ele_mem; ulong ele_footprint;
37 : void * obj_mem; ulong obj_footprint;
38 :
39 : ulong * snapin_manif_fseq;
40 :
41 : struct io_uring * ring;
42 : # if FD_HAS_LIBURING
43 : struct io_uring _ring[1];
44 : # endif
45 : };
46 :
47 : typedef struct fd_vinyl_tile_ctx fd_vinyl_tile_ctx_t;
48 :
49 : #if FD_HAS_LIBURING
50 :
51 : static struct io_uring_params *
52 : vinyl_io_uring_params( struct io_uring_params * params,
53 : uint uring_depth ) {
54 : memset( params, 0, sizeof(struct io_uring_params) );
55 : params->flags |= IORING_SETUP_CQSIZE;
56 : params->cq_entries = uring_depth;
57 : params->flags |= IORING_SETUP_COOP_TASKRUN;
58 : params->flags |= IORING_SETUP_SINGLE_ISSUER;
59 : params->flags |= IORING_SETUP_R_DISABLED;
60 : params->features |= IORING_SETUP_DEFER_TASKRUN;
61 : return params;
62 : }
63 :
64 : #endif
65 :
66 :
67 : static ulong
68 0 : scratch_align( void ) {
69 0 : return FD_SHMEM_HUGE_PAGE_SZ;
70 0 : }
71 :
72 : static ulong
73 0 : scratch_footprint( fd_topo_tile_t const * tile ) {
74 0 : (void)tile;
75 0 : ulong l = FD_LAYOUT_INIT;
76 0 : l = FD_LAYOUT_APPEND( l, alignof(fd_vinyl_tile_ctx_t), sizeof(fd_vinyl_tile_ctx_t) );
77 0 : if( tile->vinyl.io_type==FD_VINYL_IO_TYPE_UR ) {
78 : # if FD_HAS_LIBURING
79 : l = FD_LAYOUT_APPEND( l, fd_vinyl_io_ur_align(), fd_vinyl_io_ur_footprint( IO_SPAD_MAX ) );
80 : # endif
81 0 : } else {
82 0 : l = FD_LAYOUT_APPEND( l, fd_vinyl_io_bd_align(), fd_vinyl_io_bd_footprint( IO_SPAD_MAX ) );
83 0 : }
84 0 : l = FD_LAYOUT_APPEND( l, fd_vinyl_align(), fd_vinyl_footprint() );
85 0 : l = FD_LAYOUT_APPEND( l, fd_cnc_align(), fd_cnc_footprint( FD_VINYL_CNC_APP_SZ ) );
86 0 : l = FD_LAYOUT_APPEND( l, alignof(fd_vinyl_line_t), sizeof(fd_vinyl_line_t)*tile->vinyl.vinyl_line_max );
87 0 : return FD_LAYOUT_FINI( l, scratch_align() );
88 0 : }
89 :
90 : /* vinyl_init_fast is a variation of fd_vinyl_init. Creates tile
91 : private data structures and formats shared cache objects. Reuses
92 : existing io/bstream/meta. */
93 :
94 : static void
95 : vinyl_init_fast( fd_vinyl_tile_ctx_t * ctx,
96 : void * _vinyl,
97 : void * _cnc, ulong cnc_footprint,
98 : void * _meta, ulong meta_footprint,
99 : void * _line, ulong line_footprint,
100 : void * _ele, ulong ele_footprint,
101 : void * _obj, ulong obj_footprint,
102 : fd_vinyl_io_t * io,
103 : void * obj_laddr0,
104 : ulong async_min,
105 : ulong async_max,
106 : ulong part_thresh,
107 : ulong gc_thresh,
108 0 : int gc_eager ) {
109 0 : ulong ele_max = fd_ulong_pow2_dn( ele_footprint / sizeof( fd_vinyl_meta_ele_t ) );
110 0 : ulong pair_max = ele_max - 1UL;
111 0 : ulong line_cnt = fd_ulong_min( line_footprint / sizeof( fd_vinyl_line_t ), pair_max );
112 :
113 0 : FD_TEST( (3UL<=line_cnt) & (line_cnt<=FD_VINYL_LINE_MAX) );
114 0 : FD_TEST( io );
115 0 : FD_TEST( (0UL<async_min) & (async_min<=async_max) );
116 0 : FD_TEST( (-1<=gc_eager) & (gc_eager<=63) );
117 :
118 0 : fd_vinyl_t * vinyl = (fd_vinyl_t *)_vinyl;
119 0 : memset( vinyl, 0, fd_vinyl_footprint() );
120 :
121 0 : vinyl->cnc = fd_cnc_join( fd_cnc_new( _cnc, FD_VINYL_CNC_APP_SZ, FD_VINYL_CNC_TYPE, fd_log_wallclock() ) );
122 0 : FD_TEST( vinyl->cnc );
123 0 : vinyl->line = (fd_vinyl_line_t *)_line;
124 0 : vinyl->io = io;
125 :
126 0 : vinyl->line_cnt = line_cnt;
127 0 : vinyl->pair_max = pair_max;
128 0 : vinyl->async_min = async_min;
129 0 : vinyl->async_max = async_max;
130 :
131 0 : vinyl->part_thresh = part_thresh;
132 0 : vinyl->gc_thresh = gc_thresh;
133 0 : vinyl->gc_eager = gc_eager;
134 0 : vinyl->style = FD_VINYL_BSTREAM_CTL_STYLE_RAW;
135 0 : vinyl->line_idx_lru = 0U;
136 0 : vinyl->pair_cnt = 0UL;
137 0 : vinyl->garbage_sz = 0UL;
138 :
139 0 : FD_TEST( fd_vinyl_meta_join( vinyl->meta, _meta, _ele ) );
140 :
141 0 : FD_TEST( fd_vinyl_data_init( vinyl->data, _obj, obj_footprint, obj_laddr0 ) );
142 0 : fd_vinyl_data_reset( NULL, 0UL, 0UL, 0, vinyl->data );
143 :
144 0 : vinyl->cnc_footprint = cnc_footprint;
145 0 : vinyl->meta_footprint = meta_footprint;
146 0 : vinyl->line_footprint = line_footprint;
147 0 : vinyl->ele_footprint = ele_footprint;
148 0 : vinyl->obj_footprint = obj_footprint;
149 :
150 0 : ctx->vinyl = vinyl;
151 :
152 0 : FD_LOG_NOTICE(( "Vinyl config"
153 0 : "\n\tline_cnt %lu pairs"
154 0 : "\n\tpair_max %lu pairs"
155 0 : "\n\tasync_min %lu min iterations per async"
156 0 : "\n\tasync_max %lu max iterations per async"
157 0 : "\n\tpart_thresh %lu bytes"
158 0 : "\n\tgc_thresh %lu bytes"
159 0 : "\n\tgc_eager %i",
160 0 : line_cnt, pair_max, async_min, async_max, part_thresh, gc_thresh, gc_eager ));
161 0 : }
162 :
163 : #if FD_HAS_LIBURING
164 :
165 : static void
166 : vinyl_io_uring_init( fd_vinyl_tile_ctx_t * ctx,
167 : uint uring_depth,
168 : int dev_fd ) {
169 : ctx->ring = ctx->_ring;
170 :
171 : /* Setup io_uring instance */
172 : struct io_uring_params params[1];
173 : vinyl_io_uring_params( params, uring_depth );
174 : int init_err = io_uring_queue_init_params( uring_depth, ctx->ring, params );
175 : if( FD_UNLIKELY( init_err<0 ) ) FD_LOG_ERR(( "io_uring_queue_init_params failed (%i-%s)", init_err, fd_io_strerror( -init_err ) ));
176 :
177 : /* Setup io_uring file access */
178 : FD_TEST( 0==io_uring_register_files( ctx->ring, &dev_fd, 1 ) );
179 :
180 : /* Register restrictions */
181 : struct io_uring_restriction res[3] = {
182 : { .opcode = IORING_RESTRICTION_SQE_OP,
183 : .sqe_op = IORING_OP_READ },
184 : { .opcode = IORING_RESTRICTION_SQE_FLAGS_REQUIRED,
185 : .sqe_flags = IOSQE_FIXED_FILE },
186 : { .opcode = IORING_RESTRICTION_SQE_FLAGS_ALLOWED,
187 : .sqe_flags = IOSQE_IO_LINK | IOSQE_CQE_SKIP_SUCCESS }
188 : };
189 : int res_err = io_uring_register_restrictions( ctx->ring, res, 3U );
190 : if( FD_UNLIKELY( res_err<0 ) ) FD_LOG_ERR(( "io_uring_register_restrictions failed (%i-%s)", res_err, fd_io_strerror( -res_err ) ));
191 :
192 : /* Enable rings */
193 : int enable_err = io_uring_enable_rings( ctx->ring );
194 : if( FD_UNLIKELY( enable_err<0 ) ) FD_LOG_ERR(( "io_uring_enable_rings failed (%i-%s)", enable_err, fd_io_strerror( -enable_err ) ));
195 : }
196 :
197 : #else /* no io_uring */
198 :
199 : static void
200 : vinyl_io_uring_init( fd_vinyl_tile_ctx_t * ctx,
201 : uint uring_depth,
202 0 : int dev_fd ) {
203 0 : (void)ctx; (void)uring_depth; (void)dev_fd;
204 0 : FD_LOG_ERR(( "Sorry, this build does not support io_uring" ));
205 0 : }
206 :
207 : #endif
208 :
209 : static void
210 : privileged_init( fd_topo_t * topo,
211 0 : fd_topo_tile_t * tile ) {
212 0 : ulong cnc_footprint = fd_cnc_footprint( FD_VINYL_CNC_APP_SZ );
213 0 : ulong line_footprint;
214 0 : if( FD_UNLIKELY( !tile->vinyl.vinyl_line_max || __builtin_umull_overflow( tile->vinyl.vinyl_line_max, sizeof(fd_vinyl_line_t), &line_footprint ) ) ) {
215 0 : FD_LOG_ERR(( "invalid vinyl_line_max %lu", tile->vinyl.vinyl_line_max ));
216 0 : }
217 :
218 0 : void * tile_mem = fd_topo_obj_laddr( topo, tile->tile_obj_id );
219 0 : FD_SCRATCH_ALLOC_INIT( l, tile_mem );
220 0 : fd_vinyl_tile_ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_vinyl_tile_ctx_t), sizeof(fd_vinyl_tile_ctx_t) );
221 0 : void * _io = NULL;
222 0 : if( tile->vinyl.io_type==FD_VINYL_IO_TYPE_UR ) {
223 : # if FD_HAS_LIBURING
224 : _io = FD_SCRATCH_ALLOC_APPEND( l, fd_vinyl_io_ur_align(), fd_vinyl_io_ur_footprint( IO_SPAD_MAX ) );
225 : # endif
226 0 : } else {
227 0 : _io = FD_SCRATCH_ALLOC_APPEND( l, fd_vinyl_io_bd_align(), fd_vinyl_io_bd_footprint( IO_SPAD_MAX ) );
228 0 : }
229 0 : void * vinyl_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_vinyl_align(), fd_vinyl_footprint() );
230 0 : void * _cnc = FD_SCRATCH_ALLOC_APPEND( l, fd_cnc_align(), cnc_footprint );
231 0 : fd_vinyl_line_t * _line = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_vinyl_line_t), line_footprint );
232 0 : ulong _end = FD_SCRATCH_ALLOC_FINI( l, scratch_align() );
233 0 : FD_TEST( (ulong)tile_mem==(ulong)ctx );
234 0 : FD_TEST( (ulong)_end-(ulong)tile_mem==scratch_footprint( tile ) );
235 :
236 0 : memset( ctx, 0, sizeof(fd_vinyl_tile_ctx_t) );
237 :
238 0 : void * _meta = fd_topo_obj_laddr( topo, tile->vinyl.vinyl_meta_map_obj_id );
239 0 : void * _ele = fd_topo_obj_laddr( topo, tile->vinyl.vinyl_meta_pool_obj_id );
240 0 : void * _obj = fd_topo_obj_laddr( topo, tile->vinyl.vinyl_data_obj_id );
241 :
242 0 : ctx->io_mem = _io;
243 0 : ctx->vinyl_mem = vinyl_mem;
244 0 : ctx->cnc_mem = _cnc; ctx->cnc_footprint = cnc_footprint;
245 0 : ctx->meta_mem = _meta; ctx->meta_footprint = topo->objs[ tile->vinyl.vinyl_meta_map_obj_id ].footprint;
246 0 : ctx->line_mem = _line; ctx->line_footprint = line_footprint;
247 0 : ctx->ele_mem = _ele; ctx->ele_footprint = topo->objs[ tile->vinyl.vinyl_meta_pool_obj_id ].footprint;
248 0 : ctx->obj_mem = _obj; ctx->obj_footprint = topo->objs[ tile->vinyl.vinyl_data_obj_id ].footprint;
249 :
250 : /* FIXME use O_DIRECT? */
251 0 : int dev_fd = open( tile->vinyl.vinyl_bstream_path, O_RDWR|O_CLOEXEC );
252 0 : if( FD_UNLIKELY( dev_fd<0 ) ) FD_LOG_ERR(( "open(%s,O_RDWR|O_CLOEXEC) failed (%i-%s)", tile->vinyl.vinyl_bstream_path, errno, fd_io_strerror( errno ) ));
253 :
254 0 : ctx->bstream_fd = dev_fd;
255 :
256 0 : int io_type = tile->vinyl.io_type;
257 0 : if( io_type==FD_VINYL_IO_TYPE_UR ) {
258 0 : vinyl_io_uring_init( ctx, tile->vinyl.uring_depth, dev_fd );
259 0 : } else if( io_type!=FD_VINYL_IO_TYPE_BD ) {
260 0 : FD_LOG_ERR(( "Unsupported vinyl io_type %d", io_type ));
261 0 : }
262 0 : }
263 :
264 : static void
265 : unprivileged_init( fd_topo_t * topo,
266 0 : fd_topo_tile_t * tile ) {
267 :
268 0 : fd_vinyl_tile_ctx_t * ctx = fd_topo_obj_laddr( topo, tile->tile_obj_id );
269 :
270 0 : ulong manif_in_idx = fd_topo_find_tile_in_link( topo, tile, "snapin_manif", 0UL );
271 0 : FD_TEST( manif_in_idx!=ULONG_MAX );
272 0 : FD_TEST( manif_in_idx<MAX_INS );
273 0 : ctx->in_kind[ manif_in_idx ] = IN_KIND_SNAP;
274 :
275 : /* Join a public CNC if provided (development only) */
276 0 : if( tile->vinyl.vinyl_cnc_obj_id!=ULONG_MAX ) {
277 0 : ctx->cnc_mem = fd_topo_obj_laddr( topo, tile->vinyl.vinyl_cnc_obj_id );
278 0 : ctx->cnc_footprint = topo->objs[ tile->vinyl.vinyl_cnc_obj_id ].footprint;
279 0 : }
280 :
281 0 : fd_topo_link_t const * in_link = &topo->links[ tile->in_link_id[ 0 ] ];
282 0 : FD_TEST( in_link && 0==strcmp( in_link->name, "snapin_manif" ) );
283 0 : if( FD_UNLIKELY( !tile->in_link_reliable[ 0 ] ) ) FD_LOG_ERR(( "tile `" NAME "` in link 0 must be reliable" ));
284 0 : ctx->snapin_manif_fseq = tile->in_link_fseq[ 0 ];
285 0 : }
286 :
287 : __attribute__((noreturn)) static void
288 0 : enter_vinyl_exec( fd_vinyl_tile_ctx_t * ctx ) {
289 :
290 0 : fd_vinyl_io_t * io = NULL;
291 0 : if( ctx->ring ) {
292 0 : io = fd_vinyl_io_ur_init( ctx->io_mem, IO_SPAD_MAX, ctx->bstream_fd, ctx->ring );
293 0 : if( FD_UNLIKELY( !io ) ) FD_LOG_ERR(( "Failed to initialize io_uring I/O backend for account database" ));
294 0 : } else {
295 0 : io = fd_vinyl_io_bd_init( ctx->io_mem, IO_SPAD_MAX, ctx->bstream_fd, 0, NULL, 0UL, 0UL );
296 0 : if( FD_UNLIKELY( !io ) ) FD_LOG_ERR(( "Failed to initialize blocking I/O backend for account database" ));
297 0 : }
298 :
299 0 : ulong async_min = 5UL;
300 0 : ulong async_max = 2*async_min;
301 0 : ulong part_thresh = 64UL<<20;
302 0 : ulong gc_thresh = 128UL<<20;
303 0 : int gc_eager = 2;
304 :
305 0 : vinyl_init_fast(
306 0 : ctx,
307 0 : ctx->vinyl_mem,
308 0 : ctx->cnc_mem, ctx->cnc_footprint,
309 0 : ctx->meta_mem, ctx->meta_footprint,
310 0 : ctx->line_mem, ctx->line_footprint,
311 0 : ctx->ele_mem, ctx->ele_footprint,
312 0 : ctx->obj_mem, ctx->obj_footprint,
313 0 : io,
314 0 : fd_wksp_containing( ctx->obj_mem ),
315 0 : async_min, async_max,
316 0 : part_thresh,
317 0 : gc_thresh,
318 0 : gc_eager );
319 :
320 0 : fd_vinyl_line_t * line = ctx->vinyl->line;
321 0 : ulong const line_cnt = ctx->vinyl->line_cnt;
322 0 : for( ulong line_idx=0UL; line_idx<line_cnt; line_idx++ ) {
323 0 : line[ line_idx ].obj = NULL;
324 0 : line[ line_idx ].ele_idx = ULONG_MAX;
325 0 : line[ line_idx ].ctl = fd_vinyl_line_ctl( 0UL, 0L);
326 0 : line[ line_idx ].line_idx_older = (uint)fd_ulong_if( line_idx!=0UL, line_idx-1UL, line_cnt-1UL );
327 0 : line[ line_idx ].line_idx_newer = (uint)fd_ulong_if( line_idx!=line_cnt-1UL, line_idx+1UL, 0UL );
328 0 : }
329 :
330 0 : fd_vinyl_exec( ctx->vinyl );
331 0 : FD_LOG_CRIT(( "Vinyl tile stopped unexpectedly" ));
332 0 : }
333 :
334 : static void
335 : on_genesis_ctrl( fd_vinyl_tile_ctx_t * ctx,
336 0 : ulong sig ) {
337 0 : (void)ctx; (void)sig;
338 0 : FD_LOG_ERR(( "Sorry, booting off vinyl is not yet supported" ));
339 0 : }
340 :
341 : static void
342 : on_snap_ctrl( fd_vinyl_tile_ctx_t * ctx,
343 0 : ulong sig ) {
344 0 : ulong msg_type = fd_ssmsg_sig_message( sig );
345 0 : if( msg_type==FD_SSMSG_DONE ) {
346 0 : FD_LOG_INFO(( "Vinyl tile booting" ));
347 0 : fd_fseq_update( ctx->snapin_manif_fseq, ULONG_MAX-1UL ); /* mark consumer as shut down */
348 0 : enter_vinyl_exec( ctx );
349 0 : }
350 0 : }
351 :
352 : static inline void
353 : during_frag( fd_vinyl_tile_ctx_t * ctx,
354 : ulong in_idx,
355 : ulong seq,
356 : ulong sig,
357 : ulong chunk,
358 : ulong sz FD_PARAM_UNUSED,
359 0 : ulong ctl FD_PARAM_UNUSED ) {
360 0 : (void)seq; (void)chunk;
361 0 : switch( ctx->in_kind[ in_idx ] ) {
362 0 : case IN_KIND_GENESIS:
363 0 : on_genesis_ctrl( ctx, sig );
364 0 : break;
365 0 : case IN_KIND_SNAP:
366 0 : on_snap_ctrl( ctx, sig );
367 0 : break;
368 0 : default:
369 0 : FD_LOG_CRIT(( "Frag from unexpected in_idx %lu", in_idx ));
370 0 : }
371 0 : }
372 :
373 0 : #define STEM_BURST (1UL)
374 0 : #define STEM_CALLBACK_CONTEXT_TYPE fd_vinyl_tile_ctx_t
375 0 : #define STEM_CALLBACK_CONTEXT_ALIGN fd_vinyl_align()
376 0 : #define STEM_CALLBACK_DURING_FRAG during_frag
377 :
378 : #include "../../disco/stem/fd_stem.c"
379 :
380 : fd_topo_run_tile_t fd_tile_vinyl = {
381 : .name = NAME,
382 : .scratch_align = scratch_align,
383 : .scratch_footprint = scratch_footprint,
384 : .privileged_init = privileged_init,
385 : .unprivileged_init = unprivileged_init,
386 : .run = stem_run
387 : };
388 :
389 : #undef NAME
|