From 2a9bbeb0dd8cab27738e31e20c2c3f4ca735e988 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Sat, 20 Nov 2021 06:14:58 +0000
Subject: [PATCH v3] 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  | 32 ++++++++++++++++++++++++++++++++
 2 files changed, 41 insertions(+)

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
     <literal>.partial</literal>. If those files need to be read, <literal>.partial</literal>
     suffix needs to be removed from the file name.
   </para>
+
+  <para>
+    When <option>--follow</option> is used with <option>--stats</option> and
+    the <application>pg_waldump</application> is terminated or interrupted
+    with signal <systemitem>SIGINT</systemitem> or <systemitem>SIGTERM</systemitem>
+    or <systemitem>SIGQUIT</systemitem>, the summary statistics computed
+    as of the termination will be displayed.
+  </para>
+
  </refsect1>
 
  <refsect1>
diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c
index 1e3894b9c4..a3d80feda0 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 <dirent.h>
+#include <signal.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
@@ -28,6 +29,7 @@
 static const char *progname;
 
 static int	WalSegSz;
+static volatile sig_atomic_t TerminationRequestPending = false;
 
 typedef struct XLogDumpPrivate
 {
@@ -67,12 +69,20 @@ 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)
 
+static void
+SignalHandlerForTermination(int signum)
+{
+	TerminationRequestPending = true;
+}
+
 static void
 print_rmgr_list(void)
 {
@@ -645,6 +655,9 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats)
 	}
 	total_len = total_rec_len + total_fpi_len;
 
+	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%)")
@@ -794,6 +807,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]);
@@ -833,6 +850,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 +1104,14 @@ 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 (TerminationRequestPending)
+			break;
+
 		/* try to read the next record */
 		record = XLogReadRecord(xlogreader_state, &errormsg);
 		if (!record)
@@ -1112,7 +1138,10 @@ main(int argc, char **argv)
 		if (!config.quiet)
 		{
 			if (config.stats == true)
+			{
 				XLogDumpCountRecord(&config, &stats, xlogreader_state);
+				stats.endptr = xlogreader_state->currRecPtr;
+			}
 			else
 				XLogDumpDisplayRecord(&config, xlogreader_state);
 		}
@@ -1127,6 +1156,9 @@ main(int argc, char **argv)
 	if (config.stats == true && !config.quiet)
 		XLogDumpDisplayStats(&config, &stats);
 
+	if (TerminationRequestPending)
+		return EXIT_FAILURE;
+
 	if (errormsg)
 		fatal_error("error in WAL record at %X/%X: %s",
 					LSN_FORMAT_ARGS(xlogreader_state->ReadRecPtr),
-- 
2.25.1

