Skip to content

Commit f2c52ee

Browse files
committed
pg_waldump: Emit stats summary when interrupted by SIGINT
Previously, pg_waldump would not display its statistics summary if it got interrupted by SIGINT (or say a simple Ctrl+C). It gains with this commit a signal handler for SIGINT, trapping the signal to exit at the earliest convenience to allow a display of the stats summary before exiting. This makes the reports more interactive, similarly to strace -c. This new behavior makes the combination of the options --stats and --follow much more useful, so as the user will get a report for any invocation of pg_waldump in such a case. Information about the LSN range of the stats computed is added as a header to the report displayed. This implementation comes from a suggestion by Álvaro Herrera and myself, following a complaint by the author of this patch about --stats and --follow not being useful together originally. As documented, this is not supported on Windows, though its support would be possible by catching the terminal events associated to Ctrl+C, for example (this may require a more centralized implementation, as other tools could benefit from a common API). Author: Bharath Rupireddy Discussion: https://postgr.es/m/CALj2ACUUx3PcK2z9h0_m7vehreZAUbcmOky9WSEpe8TofhV=PQ@mail.gmail.com
1 parent 0df9641 commit f2c52ee

File tree

2 files changed

+57
-0
lines changed

2 files changed

+57
-0
lines changed

doc/src/sgml/ref/pg_waldump.sgml

+9
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,15 @@ PostgreSQL documentation
202202
full-page images) instead of individual records. Optionally
203203
generate statistics per-record instead of per-rmgr.
204204
</para>
205+
206+
<para>
207+
If <application>pg_waldump</application> is terminated by signal
208+
<systemitem>SIGINT</systemitem>
209+
(<keycombo action="simul"><keycap>Control</keycap><keycap>C</keycap></keycombo>,
210+
the summary of the statistics computed is displayed up to the
211+
termination point. This operation is not supported on
212+
<productname>Windows</productname>.
213+
</para>
205214
</listitem>
206215
</varlistentry>
207216

src/bin/pg_waldump/pg_waldump.c

+48
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "postgres.h"
1414

1515
#include <dirent.h>
16+
#include <signal.h>
1617
#include <sys/stat.h>
1718
#include <unistd.h>
1819

@@ -28,6 +29,7 @@
2829
static const char *progname;
2930

3031
static int WalSegSz;
32+
static volatile sig_atomic_t time_to_stop = false;
3133

3234
typedef struct XLogDumpPrivate
3335
{
@@ -67,12 +69,27 @@ typedef struct Stats
6769
typedef struct XLogDumpStats
6870
{
6971
uint64 count;
72+
XLogRecPtr startptr;
73+
XLogRecPtr endptr;
7074
Stats rmgr_stats[RM_NEXT_ID];
7175
Stats record_stats[RM_NEXT_ID][MAX_XLINFO_TYPES];
7276
} XLogDumpStats;
7377

7478
#define fatal_error(...) do { pg_log_fatal(__VA_ARGS__); exit(EXIT_FAILURE); } while(0)
7579

80+
/*
81+
* When sigint is called, just tell the system to exit at the next possible
82+
* moment.
83+
*/
84+
#ifndef WIN32
85+
86+
static void
87+
sigint_handler(int signum)
88+
{
89+
time_to_stop = true;
90+
}
91+
#endif
92+
7693
static void
7794
print_rmgr_list(void)
7895
{
@@ -632,6 +649,12 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats)
632649
double rec_len_pct,
633650
fpi_len_pct;
634651

652+
/*
653+
* Leave if no stats have been computed yet, as tracked by the end LSN.
654+
*/
655+
if (XLogRecPtrIsInvalid(stats->endptr))
656+
return;
657+
635658
/*
636659
* Each row shows its percentages of the total, so make a first pass to
637660
* calculate column totals.
@@ -645,6 +668,9 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats)
645668
}
646669
total_len = total_rec_len + total_fpi_len;
647670

671+
printf("WAL statistics between %X/%X and %X/%X:\n",
672+
LSN_FORMAT_ARGS(stats->startptr), LSN_FORMAT_ARGS(stats->endptr));
673+
648674
/*
649675
* 27 is strlen("Transaction/COMMIT_PREPARED"), 20 is strlen(2^64), 8 is
650676
* strlen("(100.00%)")
@@ -794,6 +820,10 @@ main(int argc, char **argv)
794820
int option;
795821
int optindex = 0;
796822

823+
#ifndef WIN32
824+
pqsignal(SIGINT, sigint_handler);
825+
#endif
826+
797827
pg_logging_init(argv[0]);
798828
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_waldump"));
799829
progname = get_progname(argv[0]);
@@ -833,6 +863,9 @@ main(int argc, char **argv)
833863
config.stats = false;
834864
config.stats_per_record = false;
835865

866+
stats.startptr = InvalidXLogRecPtr;
867+
stats.endptr = InvalidXLogRecPtr;
868+
836869
if (argc <= 1)
837870
{
838871
pg_log_error("no arguments specified");
@@ -1084,8 +1117,17 @@ main(int argc, char **argv)
10841117
LSN_FORMAT_ARGS(first_record),
10851118
(uint32) (first_record - private.startptr));
10861119

1120+
if (config.stats == true && !config.quiet)
1121+
stats.startptr = first_record;
1122+
10871123
for (;;)
10881124
{
1125+
if (time_to_stop)
1126+
{
1127+
/* We've been Ctrl-C'ed, so leave */
1128+
break;
1129+
}
1130+
10891131
/* try to read the next record */
10901132
record = XLogReadRecord(xlogreader_state, &errormsg);
10911133
if (!record)
@@ -1112,7 +1154,10 @@ main(int argc, char **argv)
11121154
if (!config.quiet)
11131155
{
11141156
if (config.stats == true)
1157+
{
11151158
XLogDumpCountRecord(&config, &stats, xlogreader_state);
1159+
stats.endptr = xlogreader_state->EndRecPtr;
1160+
}
11161161
else
11171162
XLogDumpDisplayRecord(&config, xlogreader_state);
11181163
}
@@ -1127,6 +1172,9 @@ main(int argc, char **argv)
11271172
if (config.stats == true && !config.quiet)
11281173
XLogDumpDisplayStats(&config, &stats);
11291174

1175+
if (time_to_stop)
1176+
exit(0);
1177+
11301178
if (errormsg)
11311179
fatal_error("error in WAL record at %X/%X: %s",
11321180
LSN_FORMAT_ARGS(xlogreader_state->ReadRecPtr),

0 commit comments

Comments
 (0)