From f879d58dd8beb8408563baf8b40634628b5f2086 Mon Sep 17 00:00:00 2001 From: Bharath Rupireddy Date: Sat, 20 Nov 2021 04:31:11 +0000 Subject: [PATCH v2] pg_waldump: emit stats while terminating Currently, pg_waldump keeps accumulating the stats with options --follow and --stats, but outputs nothing while terminating/exiting. This patch adds signal handlers for SIGINT, SIGTERM and SIGQUIT to display the stats computed as of the termination. --- doc/src/sgml/ref/pg_waldump.sgml | 9 ++++ src/bin/pg_waldump/pg_waldump.c | 84 ++++++++++++++++++++++++-------- 2 files changed, 74 insertions(+), 19 deletions(-) diff --git a/doc/src/sgml/ref/pg_waldump.sgml b/doc/src/sgml/ref/pg_waldump.sgml index 432254d2d5..cf75d1dd21 100644 --- a/doc/src/sgml/ref/pg_waldump.sgml +++ b/doc/src/sgml/ref/pg_waldump.sgml @@ -261,6 +261,15 @@ PostgreSQL documentation .partial. If those files need to be read, .partial suffix needs to be removed from the file name. + + + When is used with and + the pg_waldump is terminated or interrupted + with signal SIGINT or SIGTERM + or SIGQUIT, the summary statistics computed + as of the termination will be displayed. + + diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c index 1e3894b9c4..d7ec48a658 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 @@ -25,10 +26,8 @@ #include "getopt_long.h" #include "rmgrdesc.h" -static const char *progname; - -static int WalSegSz; - +#define MAX_XLINFO_TYPES 16 +#define fatal_error(...) do { pg_log_fatal(__VA_ARGS__); exit(EXIT_FAILURE); } while(0) typedef struct XLogDumpPrivate { TimeLineID timeline; @@ -62,8 +61,6 @@ typedef struct Stats uint64 fpi_len; } Stats; -#define MAX_XLINFO_TYPES 16 - typedef struct XLogDumpStats { uint64 count; @@ -71,7 +68,35 @@ typedef struct XLogDumpStats Stats record_stats[RM_NEXT_ID][MAX_XLINFO_TYPES]; } XLogDumpStats; -#define fatal_error(...) do { pg_log_fatal(__VA_ARGS__); exit(EXIT_FAILURE); } while(0) +static const char *progname; +static int WalSegSz; +static XLogDumpConfig *opts = NULL; +static XLogDumpStats *stats = NULL; +static XLogRecPtr stats_startptr = InvalidXLogRecPtr; +static XLogRecPtr stats_endptr = InvalidXLogRecPtr; + +static void XLogDumpDisplayStats(void); + +static void +SignalHandlerForTermination(int signum) +{ + /* Display the stats only if they are valid */ + if (stats && + !XLogRecPtrIsInvalid(stats_startptr) && + !XLogRecPtrIsInvalid(stats_endptr)) + { + XLogDumpDisplayStats(); + pg_free(stats); + } + + /* + * Although the pg_free calls (above and below) are unnecessary here on the + * process exit, let's not leak any memory knowingly. + */ + pg_free(opts); + + exit(EXIT_FAILURE); +} static void print_rmgr_list(void) @@ -410,8 +435,7 @@ XLogDumpRecordLen(XLogReaderState *record, uint32 *rec_len, uint32 *fpi_len) * Store per-rmgr and per-record statistics for a given record. */ static void -XLogDumpCountRecord(XLogDumpConfig *config, XLogDumpStats *stats, - XLogReaderState *record) +XLogDumpCountRecord(XLogReaderState *record) { RmgrId rmid; uint8 recid; @@ -457,7 +481,7 @@ XLogDumpCountRecord(XLogDumpConfig *config, XLogDumpStats *stats, * Print a record to stdout */ static void -XLogDumpDisplayRecord(XLogDumpConfig *config, XLogReaderState *record) +XLogDumpDisplayRecord(XLogReaderState *record) { const char *id; const RmgrDescData *desc = &RmgrDescTable[XLogRecGetRmid(record)]; @@ -491,7 +515,7 @@ XLogDumpDisplayRecord(XLogDumpConfig *config, XLogReaderState *record) printf("%s", s.data); pfree(s.data); - if (!config->bkp_details) + if (!opts->bkp_details) { /* print block references (short format) */ for (block_id = 0; block_id <= record->max_block_id; block_id++) @@ -621,7 +645,7 @@ XLogDumpStatsRow(const char *name, * Display summary statistics about the records seen so far. */ static void -XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats) +XLogDumpDisplayStats(void) { int ri, rj; @@ -645,6 +669,12 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats) } total_len = total_rec_len + total_fpi_len; + Assert(!XLogRecPtrIsInvalid(stats_startptr) && + !XLogRecPtrIsInvalid(stats_endptr) && + stats_startptr <= stats_endptr); + + printf("Summary of the WAL statistics computed between LSN %X/%X and LSN %X/%X is:\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%)") @@ -663,7 +693,7 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats) tot_len; const RmgrDescData *desc = &RmgrDescTable[ri]; - if (!config->stats_per_record) + if (!opts->stats_per_record) { count = stats->rmgr_stats[ri].count; rec_len = stats->rmgr_stats[ri].rec_len; @@ -768,7 +798,6 @@ main(int argc, char **argv) XLogReaderState *xlogreader_state; XLogDumpPrivate private; XLogDumpConfig config; - XLogDumpStats stats; XLogRecord *record; XLogRecPtr first_record; char *waldir = NULL; @@ -794,6 +823,10 @@ main(int argc, char **argv) int option; int optindex = 0; + pqsignal(SIGINT, SignalHandlerForTermination); + pqsignal(SIGTERM, SignalHandlerForTermination); + pqsignal(SIGQUIT, SignalHandlerForTermination); + pg_logging_init(argv[0]); set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_waldump")); progname = get_progname(argv[0]); @@ -813,8 +846,8 @@ main(int argc, char **argv) } memset(&private, 0, sizeof(XLogDumpPrivate)); - memset(&config, 0, sizeof(XLogDumpConfig)); - memset(&stats, 0, sizeof(XLogDumpStats)); + opts = (XLogDumpConfig *) pg_malloc0(sizeof(XLogDumpConfig)); + config = *opts; private.timeline = 1; private.startptr = InvalidXLogRecPtr; @@ -1084,6 +1117,12 @@ main(int argc, char **argv) LSN_FORMAT_ARGS(first_record), (uint32) (first_record - private.startptr)); + if (config.stats == true && !config.quiet) + { + stats = (XLogDumpStats *) pg_malloc0(sizeof(XLogDumpStats)); + stats_startptr = first_record; + } + for (;;) { /* try to read the next record */ @@ -1112,9 +1151,12 @@ main(int argc, char **argv) if (!config.quiet) { if (config.stats == true) - XLogDumpCountRecord(&config, &stats, xlogreader_state); + { + XLogDumpCountRecord(xlogreader_state); + stats_endptr = xlogreader_state->currRecPtr; + } else - XLogDumpDisplayRecord(&config, xlogreader_state); + XLogDumpDisplayRecord(xlogreader_state); } /* check whether we printed enough */ @@ -1125,7 +1167,7 @@ main(int argc, char **argv) } if (config.stats == true && !config.quiet) - XLogDumpDisplayStats(&config, &stats); + XLogDumpDisplayStats(); if (errormsg) fatal_error("error in WAL record at %X/%X: %s", @@ -1134,9 +1176,13 @@ main(int argc, char **argv) XLogReaderFree(xlogreader_state); + pg_free(opts); + pg_free(stats); + return EXIT_SUCCESS; bad_argument: fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); + pg_free(opts); return EXIT_FAILURE; } -- 2.25.1