diff --git a/doc/src/sgml/ref/pg_waldump.sgml b/doc/src/sgml/ref/pg_waldump.sgml index 432254d2d5..5735a161ce 100644 --- a/doc/src/sgml/ref/pg_waldump.sgml +++ b/doc/src/sgml/ref/pg_waldump.sgml @@ -202,6 +202,15 @@ PostgreSQL documentation full-page images) instead of individual records. Optionally generate statistics per-record instead of per-rmgr. + + + If pg_waldump is terminated by signal + SIGINT + (ControlC, + the summary of the statistics computed is displayed up to the + termination point. This operation is not supported on + Windows. + diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c index 4690e0f515..f66b5a8dba 100644 --- a/src/bin/pg_waldump/pg_waldump.c +++ b/src/bin/pg_waldump/pg_waldump.c @@ -13,6 +13,7 @@ #include "postgres.h" #include +#include #include #include @@ -28,6 +29,7 @@ static const char *progname; static int WalSegSz; +static volatile sig_atomic_t time_to_stop = false; typedef struct XLogDumpPrivate { @@ -67,12 +69,27 @@ typedef struct Stats typedef struct XLogDumpStats { uint64 count; + XLogRecPtr startptr; + XLogRecPtr endptr; Stats rmgr_stats[RM_NEXT_ID]; Stats record_stats[RM_NEXT_ID][MAX_XLINFO_TYPES]; } XLogDumpStats; #define fatal_error(...) do { pg_log_fatal(__VA_ARGS__); exit(EXIT_FAILURE); } while(0) +/* + * When sigint is called, just tell the system to exit at the next possible + * moment. + */ +#ifndef WIN32 + +static void +sigint_handler(int signum) +{ + time_to_stop = true; +} +#endif + static void print_rmgr_list(void) { @@ -632,6 +649,12 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats) double rec_len_pct, fpi_len_pct; + /* + * Leave if no stats have been computed yet, as tracked by the end LSN. + */ + if (XLogRecPtrIsInvalid(stats->endptr)) + return; + /* * Each row shows its percentages of the total, so make a first pass to * calculate column totals. @@ -645,6 +668,9 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats) } total_len = total_rec_len + total_fpi_len; + printf("WAL statistics between %X/%X and %X/%X:\n", + LSN_FORMAT_ARGS(stats->startptr), LSN_FORMAT_ARGS(stats->endptr)); + /* * 27 is strlen("Transaction/COMMIT_PREPARED"), 20 is strlen(2^64), 8 is * strlen("(100.00%)") @@ -794,6 +820,10 @@ main(int argc, char **argv) int option; int optindex = 0; +#ifndef WIN32 + pqsignal(SIGINT, sigint_handler); +#endif + pg_logging_init(argv[0]); set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_waldump")); progname = get_progname(argv[0]); @@ -833,6 +863,9 @@ main(int argc, char **argv) config.stats = false; config.stats_per_record = false; + stats.startptr = InvalidXLogRecPtr; + stats.endptr = InvalidXLogRecPtr; + if (argc <= 1) { pg_log_error("no arguments specified"); @@ -1084,8 +1117,17 @@ main(int argc, char **argv) LSN_FORMAT_ARGS(first_record), (uint32) (first_record - private.startptr)); + if (config.stats == true && !config.quiet) + stats.startptr = first_record; + for (;;) { + if (time_to_stop) + { + /* We've been Ctrl-C'ed, so leave */ + break; + } + /* try to read the next record */ record = XLogReadRecord(xlogreader_state, &errormsg); if (!record) @@ -1112,7 +1154,10 @@ main(int argc, char **argv) if (!config.quiet) { if (config.stats == true) + { XLogDumpCountRecord(&config, &stats, xlogreader_state); + stats.endptr = xlogreader_state->EndRecPtr; + } else XLogDumpDisplayRecord(&config, xlogreader_state); } @@ -1127,6 +1172,9 @@ main(int argc, char **argv) if (config.stats == true && !config.quiet) XLogDumpDisplayStats(&config, &stats); + if (time_to_stop) + exit(0); + if (errormsg) fatal_error("error in WAL record at %X/%X: %s", LSN_FORMAT_ARGS(xlogreader_state->ReadRecPtr),