LCOV - code coverage report
Current view: top level - util/wksp - fd_wksp_io.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 232 349 66.5 %
Date: 2024-11-13 11:58:15 Functions: 4 5 80.0 %

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

Generated by: LCOV version 1.14