Line data Source code
1 : #include "fd_wksp_private.h"
2 :
3 : #include <errno.h>
4 : #include <unistd.h>
5 : #include <fcntl.h>
6 : #include <sys/stat.h>
7 :
8 : int
9 : fd_wksp_checkpt( fd_wksp_t * wksp,
10 : char const * path,
11 : ulong mode,
12 : int style,
13 9 : char const * uinfo ) { /* TODO: CONSIDER ALLOWING SUBSET OF TAGS */
14 :
15 9 : if( FD_UNLIKELY( !wksp ) ) {
16 0 : FD_LOG_WARNING(( "NULL wksp" ));
17 0 : return FD_WKSP_ERR_INVAL;
18 0 : }
19 :
20 9 : if( FD_UNLIKELY( !path ) ) {
21 0 : FD_LOG_WARNING(( "NULL path" ));
22 0 : return FD_WKSP_ERR_INVAL;
23 0 : }
24 :
25 9 : if( FD_UNLIKELY( mode!=(ulong)(mode_t)mode ) ) {
26 0 : FD_LOG_WARNING(( "bad mode" ));
27 0 : return FD_WKSP_ERR_INVAL;
28 0 : }
29 :
30 9 : style = fd_int_if( !!style, style, FD_WKSP_CHECKPT_STYLE_DEFAULT );
31 :
32 9 : if( FD_UNLIKELY( !uinfo ) ) uinfo = "";
33 :
34 9 : switch( style ) {
35 :
36 9 : case FD_WKSP_CHECKPT_STYLE_RAW: {
37 :
38 : //FD_LOG_INFO(( "Checkpt wksp \"%s\" to \"%s\" (mode 0%03lo), style %i, uinfo \"%s\"", wksp->name, path, mode, style, uinfo ));
39 :
40 9 : mode_t old_mask = umask( (mode_t)0 );
41 9 : int fd = open( path, O_CREAT|O_EXCL|O_WRONLY, (mode_t)mode );
42 9 : umask( old_mask );
43 9 : if( FD_UNLIKELY( fd==-1 ) ) {
44 0 : FD_LOG_WARNING(( "open(\"%s\",O_CREAT|O_EXCL|O_WRONLY,0%03lo) failed (%i-%s)", path, mode, errno, fd_io_strerror( errno ) ));
45 0 : return FD_WKSP_ERR_FAIL;
46 0 : }
47 :
48 9 : # define WBUF_ALIGN ( 4096UL)
49 18 : # define WBUF_FOOTPRINT (65536UL)
50 :
51 9 : uchar wbuf[ WBUF_FOOTPRINT ] __attribute__((aligned(WBUF_ALIGN)));
52 9 : fd_io_buffered_ostream_t checkpt[ 1 ];
53 9 : fd_io_buffered_ostream_init( checkpt, fd, wbuf, WBUF_FOOTPRINT );
54 :
55 9 : int err;
56 9 : uchar * prep;
57 :
58 9 : err = fd_wksp_private_lock( wksp ); if( FD_UNLIKELY( err ) ) goto fini; /* logs details */
59 :
60 : /* Do basic wksp checks (TODO: CONSIDER RUNNING VERIFY ON WKSP
61 : HERE AND ELIMINATING THIS CHECK AND THE CHECKS BELOW) */
62 :
63 9 : ulong data_lo = wksp->gaddr_lo;
64 9 : ulong data_hi = wksp->gaddr_hi;
65 9 : if( FD_UNLIKELY( !((0UL<data_lo) & (data_lo<=data_hi)) ) ) goto corrupt_wksp;
66 :
67 : //FD_LOG_INFO(( "Checkpt header and metadata" ));
68 :
69 9 : prep = fd_wksp_private_checkpt_prepare( checkpt, WBUF_FOOTPRINT, &err ); if( FD_UNLIKELY( !prep ) ) goto io_err;
70 9 : prep = fd_wksp_private_checkpt_ulong( prep, wksp->magic );
71 9 : prep = fd_wksp_private_checkpt_ulong( prep, (ulong)(uint)style );
72 9 : prep = fd_wksp_private_checkpt_ulong( prep, (ulong)wksp->seed );
73 9 : prep = fd_wksp_private_checkpt_ulong( prep, wksp->part_max );
74 9 : prep = fd_wksp_private_checkpt_ulong( prep, wksp->data_max );
75 9 : prep = fd_wksp_private_checkpt_ulong( prep, (ulong)fd_log_wallclock() );
76 9 : prep = fd_wksp_private_checkpt_ulong( prep, fd_log_app_id() );
77 9 : prep = fd_wksp_private_checkpt_ulong( prep, fd_log_thread_id() );
78 9 : prep = fd_wksp_private_checkpt_ulong( prep, fd_log_host_id() );
79 9 : prep = fd_wksp_private_checkpt_ulong( prep, fd_log_cpu_id() );
80 9 : prep = fd_wksp_private_checkpt_ulong( prep, fd_log_group_id() );
81 9 : prep = fd_wksp_private_checkpt_ulong( prep, fd_log_tid() );
82 9 : prep = fd_wksp_private_checkpt_ulong( prep, fd_log_user_id() );
83 9 : prep = fd_wksp_private_checkpt_buf ( prep, wksp->name, strlen( wksp->name ) );
84 9 : prep = fd_wksp_private_checkpt_buf ( prep, fd_log_app(), strlen( fd_log_app() ) );
85 9 : prep = fd_wksp_private_checkpt_buf ( prep, fd_log_thread(), strlen( fd_log_thread() ) );
86 9 : prep = fd_wksp_private_checkpt_buf ( prep, fd_log_host(), strlen( fd_log_host() ) );
87 9 : prep = fd_wksp_private_checkpt_buf ( prep, fd_log_cpu(), strlen( fd_log_cpu() ) );
88 9 : prep = fd_wksp_private_checkpt_buf ( prep, fd_log_group(), strlen( fd_log_group() ) );
89 9 : prep = fd_wksp_private_checkpt_buf ( prep, fd_log_user(), strlen( fd_log_user() ) );
90 9 : prep = fd_wksp_private_checkpt_buf ( prep, fd_log_build_info, fd_ulong_min( fd_log_build_info_sz-1UL, 16383UL ) );
91 9 : prep = fd_wksp_private_checkpt_buf ( prep, uinfo, fd_cstr_nlen( uinfo, 16383UL ) );
92 9 : fd_wksp_private_checkpt_publish( checkpt, prep );
93 :
94 : //FD_LOG_INFO(( "Checkpt allocations" ));
95 :
96 9 : ulong part_max = wksp->part_max;
97 9 : fd_wksp_private_pinfo_t * pinfo = fd_wksp_private_pinfo( wksp );
98 :
99 9 : ulong cycle_tag = wksp->cycle_tag++;
100 :
101 9 : ulong gaddr_last = data_lo;
102 :
103 9 : ulong i = fd_wksp_private_pinfo_idx( wksp->part_head_cidx );
104 45 : while( !fd_wksp_private_pinfo_idx_is_null( i ) ) {
105 36 : if( FD_UNLIKELY( i>=part_max ) || FD_UNLIKELY( pinfo[ i ].cycle_tag==cycle_tag ) ) goto corrupt_wksp;
106 36 : pinfo[ i ].cycle_tag = cycle_tag; /* mark i as visited */
107 :
108 : /* Do basic partition checks */
109 :
110 36 : ulong gaddr_lo = pinfo[ i ].gaddr_lo;
111 36 : ulong gaddr_hi = pinfo[ i ].gaddr_hi;
112 36 : ulong tag = pinfo[ i ].tag;
113 :
114 36 : if( FD_UNLIKELY( !((gaddr_last==gaddr_lo) & (gaddr_lo<gaddr_hi) & (gaddr_hi<=data_hi)) ) ) goto corrupt_wksp;
115 :
116 36 : gaddr_last = gaddr_hi;
117 :
118 : /* If an allocated partition, checkpt it */
119 :
120 36 : if( tag ) { /* ~50/50 */
121 :
122 21 : ulong sz = gaddr_hi - gaddr_lo;
123 21 : void * laddr_lo = fd_wksp_laddr_fast( wksp, gaddr_lo );
124 :
125 : /* Checkpt partition header */
126 :
127 21 : prep = fd_wksp_private_checkpt_prepare( checkpt, 3UL*9UL, &err ); if( FD_UNLIKELY( !prep ) ) goto io_err;
128 21 : prep = fd_wksp_private_checkpt_ulong( prep, tag );
129 21 : prep = fd_wksp_private_checkpt_ulong( prep, gaddr_lo );
130 21 : prep = fd_wksp_private_checkpt_ulong( prep, sz );
131 21 : fd_wksp_private_checkpt_publish( checkpt, prep );
132 :
133 : /* Checkpt partition data */
134 :
135 21 : err = fd_wksp_private_checkpt_write( checkpt, laddr_lo, sz ); if( FD_UNLIKELY( err ) ) goto io_err;
136 21 : }
137 :
138 : /* Advance to next partition */
139 :
140 36 : i = fd_wksp_private_pinfo_idx( pinfo[ i ].next_cidx );
141 36 : }
142 :
143 : //FD_LOG_INFO(( "Checkpt footer" ));
144 :
145 9 : prep = fd_wksp_private_checkpt_prepare( checkpt, 1UL*9UL, &err ); if( FD_UNLIKELY( !prep ) ) goto io_err;
146 9 : prep = fd_wksp_private_checkpt_ulong( prep, 0UL ); /* tags are never 0 above */
147 9 : fd_wksp_private_checkpt_publish( checkpt, prep );
148 :
149 9 : err = fd_io_buffered_ostream_flush( checkpt ); if( FD_UNLIKELY( err ) ) goto io_err;
150 :
151 9 : fd_wksp_private_unlock( wksp );
152 :
153 : //FD_LOG_INFO(( "Checkpt successful" ));
154 :
155 : /* note: err == 0 at this point */
156 :
157 9 : fini: /* note: wksp unlocked at this point */
158 9 : fd_io_buffered_ostream_fini( checkpt );
159 9 : if( FD_UNLIKELY( err ) && FD_UNLIKELY( unlink( path ) ) )
160 0 : FD_LOG_WARNING(( "unlink(\"%s\") failed (%i-%s); attempting to continue", path, errno, fd_io_strerror( errno ) ));
161 9 : if( FD_UNLIKELY( close( fd ) ) )
162 0 : FD_LOG_WARNING(( "close(\"%s\") failed (%i-%s); attempting to continue", path, errno, fd_io_strerror( errno ) ));
163 9 : return err;
164 :
165 0 : io_err: /* Failed due to I/O error ... clean up and log (note: wksp locked at this point) */
166 0 : fd_wksp_private_unlock( wksp );
167 0 : FD_LOG_WARNING(( "Checkpt wksp \"%s\" to \"%s\" failed due to I/O error (%i-%s)",
168 0 : wksp->name, path, err, fd_io_strerror( err ) ));
169 0 : err = FD_WKSP_ERR_FAIL;
170 0 : goto fini;
171 :
172 0 : corrupt_wksp: /* Failed due to wksp corruption ... clean up and log (note: wksp locked at this point) */
173 0 : fd_wksp_private_unlock( wksp );
174 0 : FD_LOG_WARNING(( "Checkpt wksp \"%s\" to \"%s\" failed due to wksp corruption", wksp->name, path ));
175 0 : err = FD_WKSP_ERR_CORRUPT;
176 0 : goto fini;
177 :
178 9 : # undef WBUF_FOOTPRINT
179 9 : # undef WBUF_ALIGN
180 :
181 9 : } /* FD_WKSP_CHECKPT_STYLE_RAW */
182 :
183 0 : default:
184 0 : break;
185 9 : }
186 :
187 0 : FD_LOG_WARNING(( "unsupported style" ));
188 0 : return FD_WKSP_ERR_INVAL;
189 9 : }
190 :
191 : /*********************************************************************/
192 :
193 : int
194 : fd_wksp_private_restore_ulong( fd_io_buffered_istream_t * in,
195 1095 : ulong * _val ) {
196 1095 : ulong csz;
197 1095 : uchar const * buf;
198 1095 : uchar _buf[9UL];
199 :
200 : /* Read the encoded val */
201 :
202 1095 : ulong peek_sz = fd_io_buffered_istream_peek_sz( in );
203 :
204 1095 : if( FD_LIKELY( peek_sz>=9UL ) ) { /* encoded val already prefetched */
205 1014 : buf = fd_io_buffered_istream_peek( in );
206 1014 : csz = fd_ulong_svw_dec_sz( buf );
207 1014 : fd_io_buffered_istream_seek( in, csz );
208 1014 : } else { /* encoded val not guaranteed prefetched (this will also implicitly prefetch for future restores) */
209 81 : int err;
210 81 : err = fd_io_buffered_istream_read( in, _buf, 1UL ); if( FD_UNLIKELY( err ) ) { *_val = 0UL; return err; }
211 81 : csz = fd_ulong_svw_dec_sz( _buf );
212 81 : err = fd_io_buffered_istream_read( in, _buf+1UL, csz-1UL ); if( FD_UNLIKELY( err ) ) { *_val = 0UL; return err; }
213 81 : buf = _buf;
214 81 : }
215 :
216 : /* Decode encoded val */
217 :
218 1095 : *_val = fd_ulong_svw_dec_fixed( buf, csz );
219 1095 : return 0;
220 1095 : }
221 :
222 : int
223 : fd_wksp_private_restore_buf( fd_io_buffered_istream_t * in,
224 : void * buf,
225 : ulong buf_max,
226 324 : ulong * _buf_sz ) {
227 :
228 : /* Restore buf_sz */
229 :
230 324 : ulong buf_sz;
231 324 : int err = fd_wksp_private_restore_ulong( in, &buf_sz );
232 324 : if( FD_UNLIKELY( (!!err) | (buf_sz>buf_max) ) ) { /* I/O error, unexpected EOF, or buf_max too small */
233 0 : if( !!err ) err = EPROTO; /* cmov */
234 0 : *_buf_sz = 0UL;
235 0 : return err;
236 0 : }
237 :
238 : /* Restore buf */
239 :
240 324 : err = fd_io_buffered_istream_read( in, buf, buf_sz );
241 324 : *_buf_sz = fd_ulong_if( !err, buf_sz, 0UL );
242 324 : return err;
243 324 : }
244 :
245 : /* TODO: CONSIDER ALLOWING RANGE OF TAGS? CONSIDER OPS LIKE KEEPING
246 : EXISTING PARTITIONS / REPLACE CONFLICTING / ETC? */
247 :
248 : int
249 : fd_wksp_restore( fd_wksp_t * wksp,
250 : char const * path,
251 21 : uint new_seed ) {
252 :
253 21 : if( FD_UNLIKELY( !wksp ) ) {
254 0 : FD_LOG_WARNING(( "NULL wksp" ));
255 0 : return FD_WKSP_ERR_INVAL;
256 0 : }
257 :
258 21 : if( FD_UNLIKELY( !path ) ) {
259 0 : FD_LOG_WARNING(( "NULL path" ));
260 0 : return FD_WKSP_ERR_INVAL;
261 0 : }
262 :
263 21 : FD_LOG_INFO(( "Restore checkpt \"%s\" into wksp \"%s\" (seed %u)", path, wksp->name, new_seed ));
264 :
265 21 : int fd = open( path, O_RDONLY, (mode_t)0 );
266 21 : if( FD_UNLIKELY( fd==-1 ) ) {
267 0 : FD_LOG_WARNING(( "open(\"%s\",O_RDONLY,0) failed (%i-%s)", path, errno, fd_io_strerror( errno ) ));
268 0 : return FD_WKSP_ERR_FAIL;
269 0 : }
270 :
271 21 : # define RBUF_ALIGN (4096UL)
272 21 : # define RBUF_FOOTPRINT (65536UL)
273 :
274 21 : uchar rbuf[ RBUF_FOOTPRINT ] __attribute__((aligned( RBUF_ALIGN )));
275 21 : fd_io_buffered_istream_t restore[1];
276 21 : fd_io_buffered_istream_init( restore, fd, rbuf, RBUF_FOOTPRINT );
277 :
278 21 : int err;
279 :
280 21 : err = fd_wksp_private_lock( wksp ); if( FD_UNLIKELY( err ) ) goto fini; /* logs details */
281 :
282 21 : ulong wksp_part_max = wksp->part_max;
283 21 : ulong wksp_data_max = wksp->data_max;
284 21 : ulong wksp_data_lo = wksp->gaddr_lo;
285 21 : ulong wksp_data_hi = wksp->gaddr_hi;
286 21 : fd_wksp_private_pinfo_t * wksp_pinfo = fd_wksp_private_pinfo( wksp );
287 21 : int wksp_dirty = 0;
288 :
289 21 : char const * err_info;
290 :
291 465 : # define RESTORE_ULONG(v) do { \
292 465 : err = fd_wksp_private_restore_ulong( restore, &v ); \
293 465 : if( FD_UNLIKELY( err ) ) { err_info = #v; goto io_err; } \
294 465 : } while(0)
295 :
296 189 : # define RESTORE_CSTR(v,max) do { \
297 189 : err = fd_wksp_private_restore_buf( restore, v, (max)-1UL, &v##_len ); \
298 189 : if( FD_UNLIKELY( err ) ) { err_info = #v; goto io_err; } \
299 189 : v[v##_len] = '\0'; \
300 189 : } while(0)
301 :
302 372 : # define TEST(c) do { if( FD_UNLIKELY( !(c) ) ) { err_info = #c; goto stream_err; } } while(0)
303 :
304 21 : FD_LOG_INFO(( "Restore header" ));
305 :
306 21 : ulong magic; RESTORE_ULONG( magic ); TEST( magic ==FD_WKSP_MAGIC );
307 21 : ulong style_ul; RESTORE_ULONG( style_ul ); int style = (int)(uint)style_ul; TEST( style_ul==(ulong)(uint)style );
308 :
309 21 : FD_LOG_INFO(( "checkpt_magic %016lx", magic ));
310 21 : FD_LOG_INFO(( "checkpt_style %i", style ));
311 :
312 21 : switch( style ) {
313 :
314 21 : case FD_WKSP_CHECKPT_STYLE_RAW: {
315 :
316 21 : FD_LOG_INFO(( "Restore metadata" ));
317 :
318 21 : ulong seed_ul; RESTORE_ULONG( seed_ul ); uint seed = (uint)seed_ul; TEST( seed_ul==(ulong)seed );
319 21 : ulong part_max; RESTORE_ULONG( part_max );
320 21 : ulong data_max; RESTORE_ULONG( data_max ); TEST( fd_wksp_footprint( part_max, data_max ) );
321 :
322 21 : ulong ts_ul; RESTORE_ULONG( ts_ul ); long ts = (long)ts_ul; TEST( ts_ul==(ulong)ts );
323 21 : ulong app_id; RESTORE_ULONG( app_id );
324 21 : ulong thread_id; RESTORE_ULONG( thread_id );
325 21 : ulong host_id; RESTORE_ULONG( host_id );
326 21 : ulong cpu_id; RESTORE_ULONG( cpu_id );
327 21 : ulong group_id; RESTORE_ULONG( group_id ); TEST( group_id>=2UL );
328 21 : ulong tid; RESTORE_ULONG( tid );
329 21 : ulong user_id; RESTORE_ULONG( user_id );
330 :
331 21 : char name[ FD_SHMEM_NAME_MAX ]; ulong name_len; RESTORE_CSTR( name, FD_SHMEM_NAME_MAX );
332 21 : TEST( fd_shmem_name_len( name )==name_len );
333 :
334 21 : char app [ FD_LOG_NAME_MAX ]; ulong app_len; RESTORE_CSTR( app, FD_LOG_NAME_MAX ); TEST( strlen( app )==app_len );
335 21 : char thread[ FD_LOG_NAME_MAX ]; ulong thread_len; RESTORE_CSTR( thread, FD_LOG_NAME_MAX ); TEST( strlen( thread )==thread_len );
336 21 : char host [ FD_LOG_NAME_MAX ]; ulong host_len; RESTORE_CSTR( host, FD_LOG_NAME_MAX ); TEST( strlen( host )==host_len );
337 21 : char cpu [ FD_LOG_NAME_MAX ]; ulong cpu_len; RESTORE_CSTR( cpu, FD_LOG_NAME_MAX ); TEST( strlen( cpu )==cpu_len );
338 21 : char group [ FD_LOG_NAME_MAX ]; ulong group_len; RESTORE_CSTR( group, FD_LOG_NAME_MAX ); TEST( strlen( group )==group_len );
339 21 : char user [ FD_LOG_NAME_MAX ]; ulong user_len; RESTORE_CSTR( user, FD_LOG_NAME_MAX ); TEST( strlen( user )==user_len );
340 :
341 21 : char ts_cstr[ FD_LOG_WALLCLOCK_CSTR_BUF_SZ ]; fd_log_wallclock_cstr( ts, ts_cstr );
342 :
343 21 : FD_LOG_INFO(( "checkpt_ts %-20li \"%s\"", ts, ts_cstr ));
344 21 : FD_LOG_INFO(( "checkpt_app %-20lu \"%s\"", app_id, app ));
345 21 : FD_LOG_INFO(( "checkpt_thread %-20lu \"%s\"", thread_id, thread ));
346 21 : FD_LOG_INFO(( "checkpt_host %-20lu \"%s\"", host_id, host ));
347 21 : FD_LOG_INFO(( "checkpt_cpu %-20lu \"%s\"", cpu_id, cpu ));
348 21 : FD_LOG_INFO(( "checkpt_group %-20lu \"%s\"", group_id, group ));
349 21 : FD_LOG_INFO(( "checkpt_tid %-20lu", tid ));
350 21 : FD_LOG_INFO(( "checkpt_user %-20lu \"%s\"", user_id, user ));
351 :
352 21 : char buf[ 16384 ]; ulong buf_len;
353 :
354 21 : RESTORE_CSTR( buf, 16384UL ); TEST( strlen( buf )==buf_len );
355 21 : FD_LOG_INFO(( "checkpt_build\n\t%s", buf ) );
356 :
357 21 : RESTORE_CSTR( buf, 16384UL ); TEST( strlen( buf )==buf_len );
358 21 : FD_LOG_INFO(( "checkpt_info\n\t%s", buf ));
359 :
360 21 : FD_LOG_INFO(( "shmem_name \"%s\"", name ));
361 21 : FD_LOG_INFO(( "seed %-20u", seed ));
362 21 : FD_LOG_INFO(( "part_max %-20lu", part_max ));
363 21 : FD_LOG_INFO(( "data_max %-20lu", data_max ));
364 :
365 21 : ulong data_lo = fd_wksp_private_data_off( part_max );
366 21 : ulong data_hi = data_lo + data_max;
367 :
368 21 : FD_LOG_INFO(( "Restore allocations" ));
369 :
370 21 : ulong wksp_part_cnt = 0UL;
371 :
372 78 : for(;;) {
373 :
374 : /* Restore the allocation header */
375 :
376 78 : ulong tag; RESTORE_ULONG( tag ); if( FD_UNLIKELY( !tag ) ) break; /* Optimize for lots of partitions */
377 57 : ulong gaddr_lo; RESTORE_ULONG( gaddr_lo );
378 57 : ulong sz; RESTORE_ULONG( sz );
379 :
380 57 : ulong gaddr_hi = gaddr_lo + sz;
381 :
382 57 : TEST( (data_lo<=gaddr_lo) & (gaddr_lo<gaddr_hi) & (gaddr_hi<=data_hi) );
383 :
384 57 : if( FD_UNLIKELY( wksp_part_cnt>=wksp_part_max ) ) {
385 0 : FD_LOG_WARNING(( "Restore \"%s\" to wksp \"%s\" failed because too few wksp partitions (part_max checkpt %lu, wksp %lu)",
386 0 : path, wksp->name, part_max, wksp_part_max ));
387 0 : goto unlock;
388 0 : }
389 :
390 57 : if( FD_UNLIKELY( !((wksp_data_lo<=gaddr_lo) & (gaddr_hi<=wksp_data_hi)) ) ) {
391 0 : FD_LOG_WARNING(( "Restore \"%s\" to wksp \"%s\" failed because checkpt partition [0x%016lx,0x%016lx) tag %lu "
392 0 : "does not fit into wksp data region [0x%016lx,0x%016lx) (data_max checkpt %lu, wksp %lu)",
393 0 : path, wksp->name, gaddr_lo, gaddr_hi, tag, wksp_data_lo, wksp_data_hi, data_max, wksp_data_max ));
394 0 : goto unlock;
395 0 : }
396 :
397 : /* Restore the allocation payload into the wksp and record this
398 : allocation in the wksp */
399 :
400 57 : wksp_dirty = 1;
401 :
402 : #if FD_HAS_DEEPASAN
403 : /* Poison the restored allocations. Potentially under poison to respect
404 : manual poisoning alignment requirements. Don't poison if the allocation
405 : is smaller than FD_ASAN_ALIGN. */
406 : ulong laddr_lo = (ulong)fd_wksp_laddr_fast( wksp, gaddr_lo );
407 : ulong laddr_hi = laddr_lo + sz;
408 : ulong aligned_laddr_lo = fd_ulong_align_up( laddr_lo, FD_ASAN_ALIGN );
409 : ulong aligned_laddr_hi = fd_ulong_align_dn( laddr_hi, FD_ASAN_ALIGN );
410 : if( aligned_laddr_lo < aligned_laddr_hi ) {
411 : fd_asan_poison( (void*)aligned_laddr_lo, aligned_laddr_hi - aligned_laddr_lo );
412 : }
413 : #endif
414 :
415 57 : err = fd_io_buffered_istream_read( restore, fd_wksp_laddr_fast( wksp, gaddr_lo ), sz );
416 57 : if( FD_UNLIKELY( err ) ) {
417 0 : FD_LOG_WARNING(( "Restore \"%s\" to wksp \"%s\" failed because of I/O error (%i-%s)",
418 0 : path, wksp->name, err, fd_io_strerror( err ) ));
419 0 : goto unlock;
420 0 : }
421 :
422 57 : wksp_pinfo[ wksp_part_cnt ].gaddr_lo = gaddr_lo;
423 57 : wksp_pinfo[ wksp_part_cnt ].gaddr_hi = gaddr_hi;
424 57 : wksp_pinfo[ wksp_part_cnt ].tag = tag;
425 57 : wksp_part_cnt++;
426 57 : }
427 :
428 21 : FD_LOG_INFO(( "Rebuilding wksp with restored allocations" ));
429 :
430 21 : wksp_dirty = 1;
431 :
432 343692 : for( ulong i=wksp_part_cnt; i<wksp_part_max; i++ ) wksp_pinfo[ i ].tag = 0UL; /* Remove all remaining old allocations */
433 21 : err = fd_wksp_rebuild( wksp, new_seed ); /* logs details */
434 21 : if( FD_UNLIKELY( err ) ) { /* wksp dirty */
435 0 : FD_LOG_WARNING(( "Restore \"%s\" to wksp \"%s\" failed because of rebuild error", path, wksp->name ));
436 0 : goto unlock;
437 0 : }
438 :
439 21 : wksp_dirty = 0;
440 :
441 21 : FD_LOG_INFO(( "Restore successful" ));
442 21 : break;
443 :
444 21 : } /* FD_WKSP_CHECKPT_STYLE_RAW */
445 :
446 0 : default:
447 0 : err_info = "unsupported style";
448 0 : goto stream_err;
449 21 : }
450 :
451 : /* err = 0 at this point */
452 :
453 21 : unlock: /* note: wksp locked at this point */
454 :
455 : /* If wksp is not clean, reset it to get it back to a clean state
456 : (TODO: consider FD_LOG_CRIT here if rebuild fails though it
457 : shouldn't) */
458 :
459 21 : if( wksp_dirty ) {
460 0 : FD_LOG_WARNING(( "wksp \"%s\" dirty; attempting to reset it and continue", wksp->name ));
461 0 : for( ulong i=0UL; i<wksp_part_max; i++ ) wksp_pinfo[ i ].tag = 0UL;
462 0 : fd_wksp_rebuild( wksp, new_seed ); /* logs details */
463 0 : err = FD_WKSP_ERR_CORRUPT;
464 0 : }
465 :
466 21 : fd_wksp_private_unlock( wksp );
467 :
468 21 : fini: /* Note: wksp unlocked at this point */
469 :
470 21 : fd_io_buffered_istream_fini( restore );
471 :
472 21 : if( FD_UNLIKELY( close( fd ) ) )
473 0 : FD_LOG_WARNING(( "close(\"%s\") failed (%i-%s); attempting to continue", path, errno, fd_io_strerror( errno ) ));
474 :
475 21 : return err;
476 :
477 0 : io_err: /* Note: wksp locked at this point */
478 :
479 0 : FD_LOG_WARNING(( "Restore \"%s\" to wksp \"%s\" failed (%s) due to I/O error (%i-%s)",
480 0 : path, wksp->name, err_info, err, fd_io_strerror( err ) ));
481 0 : err = FD_WKSP_ERR_FAIL;
482 :
483 0 : goto unlock;
484 :
485 0 : stream_err: /* Note: wksp locked at this point */
486 :
487 0 : FD_LOG_WARNING(( "Restore \"%s\" to wksp \"%s\" failed due to checkpt format error (%s)", path, wksp->name, err_info ));
488 0 : err = FD_WKSP_ERR_FAIL;
489 :
490 0 : goto unlock;
491 :
492 21 : # undef TEST
493 21 : # undef RESTORE_CSTR
494 21 : # undef RESTORE_ULONG
495 21 : # undef RBUF_FOOTPRINT
496 21 : # undef RBUF_ALIGN
497 21 : }
498 :
499 : int
500 : fd_wksp_restore_preview( char const * path,
501 : uint * out_seed,
502 : ulong * out_part_max,
503 0 : ulong * out_data_max ) {
504 0 : if( FD_UNLIKELY( !path ) ) {
505 0 : FD_LOG_WARNING(( "NULL path" ));
506 0 : return FD_WKSP_ERR_INVAL;
507 0 : }
508 :
509 0 : int fd = open( path, O_RDONLY, (mode_t)0 );
510 0 : if( FD_UNLIKELY( fd==-1 ) ) {
511 0 : FD_LOG_WARNING(( "open(\"%s\",O_RDONLY,0) failed (%i-%s)", path, errno, fd_io_strerror( errno ) ));
512 0 : return FD_WKSP_ERR_FAIL;
513 0 : }
514 :
515 0 : # define RBUF_ALIGN (4096UL)
516 0 : # define RBUF_FOOTPRINT (65536UL)
517 :
518 0 : uchar rbuf[ RBUF_FOOTPRINT ] __attribute__((aligned( RBUF_ALIGN )));
519 0 : fd_io_buffered_istream_t restore[1];
520 0 : fd_io_buffered_istream_init( restore, fd, rbuf, RBUF_FOOTPRINT );
521 :
522 0 : int err = FD_WKSP_SUCCESS;
523 :
524 0 : # define RESTORE_ULONG(v) do { \
525 0 : err = fd_wksp_private_restore_ulong( restore, &v ); \
526 0 : if( FD_UNLIKELY( err ) ) { goto io_err; } \
527 0 : } while(0)
528 :
529 0 : ulong magic; RESTORE_ULONG( magic );
530 0 : if( magic!=FD_WKSP_MAGIC ) { err = FD_WKSP_ERR_FAIL; goto io_err; }
531 0 : ulong style_ul; RESTORE_ULONG( style_ul ); int style = (int)(uint)style_ul;
532 :
533 0 : switch( style ) {
534 0 : case FD_WKSP_CHECKPT_STYLE_RAW: {
535 0 : ulong tseed_ul; RESTORE_ULONG( tseed_ul ); *out_seed = (uint)tseed_ul;
536 0 : ulong tpart_max; RESTORE_ULONG( tpart_max ); *out_part_max = tpart_max;
537 0 : ulong tdata_max; RESTORE_ULONG( tdata_max ); *out_data_max = tdata_max;
538 0 : break;
539 0 : } /* FD_WKSP_CHECKPT_STYLE_RAW */
540 :
541 0 : default:
542 0 : err = FD_WKSP_ERR_FAIL;
543 0 : break;
544 0 : }
545 :
546 0 : io_err:
547 0 : fd_io_buffered_istream_fini( restore );
548 :
549 0 : if( FD_UNLIKELY( close( fd ) ) )
550 0 : FD_LOG_WARNING(( "close(\"%s\") failed (%i-%s); attempting to continue", path, errno, fd_io_strerror( errno ) ));
551 :
552 0 : return err;
553 :
554 0 : #undef RESTORE_ULONG
555 0 : }
|