@@ -48,6 +48,7 @@ static volatile sig_atomic_t time_to_stop = false;
4848static const RelFileLocator emptyRelFileLocator = {0 , 0 , 0 };
4949
5050static FILE * save_records_file ;
51+ static FILE * load_records_file ;
5152
5253typedef struct XLogDumpPrivate
5354{
@@ -87,6 +88,7 @@ typedef struct XLogDumpConfig
8788 /* save options */
8889 char * save_fullpage_path ;
8990 char * save_records_file_path ;
91+ char * load_records_file_path ;
9092} XLogDumpConfig ;
9193
9294
@@ -871,24 +873,45 @@ usage(void)
871873 " (optionally, show per-record statistics)\n" ));
872874 printf (_ (" --save-fullpage=DIR save full page images to DIR\n" ));
873875 printf (_ (" --save-records=FILE save selected WAL records to the file\n" ));
876+ printf (_ (" --load-records=FILE load saved WAL records from the file\n" ));
874877 printf (_ (" -?, --help show this help, then exit\n" ));
875878 printf (_ ("\nReport bugs to <%s>.\n" ), PACKAGE_BUGREPORT );
876879 printf (_ ("%s home page: <%s>\n" ), PACKAGE_NAME , PACKAGE_URL );
877880}
878881
879882
883+ static int32
884+ read_pq_int32 (FILE * f )
885+ {
886+ int32 val ;
887+ if (fread (& val , sizeof (val ), 1 , f ) != 1 )
888+ pg_fatal ("could not read from file: %m" );
889+ return pg_hton32 (val );
890+ }
891+
892+ static int64
893+ read_pq_int64 (FILE * f )
894+ {
895+ int64 val ;
896+ if (fread (& val , sizeof (val ), 1 , f ) != 1 )
897+ pg_fatal ("could not read from file: %m" );
898+ return pg_hton64 (val );
899+ }
900+
880901static void
881902write_pq_int32 (FILE * f , int32 val )
882903{
883904 val = pg_hton32 (val );
884- fwrite (& val , sizeof (val ), 1 , f );
905+ if (fwrite (& val , sizeof (val ), 1 , f ) != 1 )
906+ pg_fatal ("could not write to file: %m" );
885907}
886908
887909static void
888910write_pq_int64 (FILE * f , int64 val )
889911{
890912 val = pg_hton64 (val );
891- fwrite (& val , sizeof (val ), 1 , f );
913+ if (fwrite (& val , sizeof (val ), 1 , f ) != 1 )
914+ pg_fatal ("could not write to file: %m" );
892915}
893916
894917static void
@@ -939,6 +962,7 @@ main(int argc, char **argv)
939962 {"stats" , optional_argument , NULL , 'z' },
940963 {"save-fullpage" , required_argument , NULL , 1 },
941964 {"save-records" , required_argument , NULL , 2 },
965+ {"load-records" , required_argument , NULL , 3 },
942966 {NULL , 0 , NULL , 0 }
943967 };
944968
@@ -993,6 +1017,7 @@ main(int argc, char **argv)
9931017 config .filter_by_fpw = false;
9941018 config .save_fullpage_path = NULL ;
9951019 config .save_records_file_path = NULL ;
1020+ config .load_records_file_path = NULL ;
9961021 config .stats = false;
9971022 config .stats_per_record = false;
9981023 config .ignore_format_errors = false;
@@ -1214,6 +1239,9 @@ main(int argc, char **argv)
12141239 case 2 :
12151240 config .save_records_file_path = pg_strdup (optarg );
12161241 break ;
1242+ case 3 :
1243+ config .load_records_file_path = pg_strdup (optarg );
1244+ break ;
12171245 default :
12181246 goto bad_argument ;
12191247 }
@@ -1317,6 +1345,9 @@ main(int argc, char **argv)
13171345 if (config .save_records_file_path )
13181346 save_records_file = fopen (config .save_records_file_path , "wb" );
13191347
1348+ if (config .load_records_file_path )
1349+ load_records_file = fopen (config .load_records_file_path , "rb" );
1350+
13201351 /* parse files as start/end boundaries, extract path if not specified */
13211352 if (optind < argc )
13221353 {
@@ -1407,7 +1438,7 @@ main(int argc, char **argv)
14071438 waldir = identify_target_directory (waldir , NULL , config .ignore_format_errors );
14081439
14091440 /* we don't know what to print */
1410- if (XLogRecPtrIsInvalid (private .startptr ) && !single_file )
1441+ if (XLogRecPtrIsInvalid (private .startptr ) && !single_file && ! load_records_file )
14111442 {
14121443 pg_log_error ("no start WAL location given" );
14131444 goto bad_argument ;
@@ -1425,6 +1456,93 @@ main(int argc, char **argv)
14251456 if (!xlogreader_state )
14261457 pg_fatal ("out of memory while allocating a WAL reading processor" );
14271458
1459+ if (load_records_file )
1460+ {
1461+ int action ;
1462+ while ((action = fgetc (load_records_file )) != EOF )
1463+ {
1464+ int len = read_pq_int32 (load_records_file );
1465+ switch (action )
1466+ {
1467+ case 'B' : /* base block */
1468+ {
1469+ int forkNum = fgetc (load_records_file );
1470+ int spcNode = read_pq_int32 (load_records_file );
1471+ int dbNode = read_pq_int32 (load_records_file );
1472+ int relNode = read_pq_int32 (load_records_file );
1473+ int blkNum = read_pq_int32 (load_records_file );
1474+ printf ("Start redo of %u/%u/%u.%u block %u\n" , spcNode , dbNode , relNode , forkNum , blkNum );
1475+ continue ;
1476+ }
1477+ case 'A' : /* apply record */
1478+ {
1479+ XLogRecPtr lsn = read_pq_int64 (load_records_file );
1480+ DecodedXLogRecord * decoded ;
1481+
1482+ record = (XLogRecord * )malloc (len - 12 );
1483+ if (fread (record , len - 12 , 1 , load_records_file ) != 1 )
1484+ pg_fatal ("could not load applied record: %m" );
1485+
1486+ XLogBeginRead (xlogreader_state , lsn );
1487+ decoded = malloc (DecodeXLogRecordRequiredSpace (record -> xl_tot_len ));
1488+ if (!DecodeXLogRecord (xlogreader_state , decoded , record , lsn , & errormsg ))
1489+ pg_fatal ("failed to decode WAL record: %s" , errormsg );
1490+
1491+ /* Record the location of the next record. */
1492+ decoded -> next_lsn = xlogreader_state -> NextRecPtr ;
1493+
1494+ /*
1495+ * Update the pointers to the beginning and one-past-the-end of this
1496+ * record, again for the benefit of historical code that expected the
1497+ * decoder to track this rather than accessing these fields of the record
1498+ * itself.
1499+ */
1500+ xlogreader_state -> record = decoded ;
1501+ xlogreader_state -> ReadRecPtr = decoded -> lsn ;
1502+ xlogreader_state -> EndRecPtr = decoded -> next_lsn ;
1503+
1504+ XLogDumpDisplayRecord (& config , xlogreader_state );
1505+
1506+ free (record );
1507+ free (decoded );
1508+ continue ;
1509+ }
1510+ case 'P' : /* push page */
1511+ {
1512+ int forkNum = fgetc (load_records_file );
1513+ int spcNode = read_pq_int32 (load_records_file );
1514+ int dbNode = read_pq_int32 (load_records_file );
1515+ int relNode = read_pq_int32 (load_records_file );
1516+ int blkNum = read_pq_int32 (load_records_file );
1517+ printf ("Base image %u/%u/%u.%u block %u\n" , spcNode , dbNode , relNode , forkNum , blkNum );
1518+ if (config .save_fullpage_path )
1519+ {
1520+ char filename [MAXPGPATH ];
1521+ char page [BLCKSZ ];
1522+ FILE * file ;
1523+ snprintf (filename , MAXPGPATH , "%s/base_image_%u.%u.%u.%u%s" , config .save_fullpage_path ,
1524+ spcNode , dbNode , relNode , blkNum , forkNames [forkNum ]);
1525+ file = fopen (filename , PG_BINARY_W );
1526+ if (!file )
1527+ pg_fatal ("could not open file \"%s\": %m" , filename );
1528+
1529+ if (fread (page , BLCKSZ , 1 , load_records_file ) != 1 ||
1530+ fwrite (page , BLCKSZ , 1 , file ) != 1 )
1531+ pg_fatal ("could not save image in file \"%s\": %m" , filename );
1532+ fclose (file );
1533+ }
1534+ continue ;
1535+ }
1536+ case 'G' : /* get page */
1537+ break ;
1538+ default :
1539+ pg_fatal ("Unexpected action: %d" , action );
1540+ }
1541+ break ;
1542+ }
1543+ goto success ;
1544+ }
1545+
14281546 if (save_records_file )
14291547 {
14301548 /*
@@ -1592,7 +1710,7 @@ main(int argc, char **argv)
15921710 pg_fatal ("error in WAL record at %X/%X: %s" ,
15931711 LSN_FORMAT_ARGS (xlogreader_state -> ReadRecPtr ),
15941712 errormsg );
1595-
1713+ success :
15961714 XLogReaderFree (xlogreader_state );
15971715
15981716 return EXIT_SUCCESS ;
0 commit comments