mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-12 18:34:36 +08:00
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
This commit is contained in:
parent
0df9641d39
commit
f2c52eeba9
@ -202,6 +202,15 @@ PostgreSQL documentation
|
|||||||
full-page images) instead of individual records. Optionally
|
full-page images) instead of individual records. Optionally
|
||||||
generate statistics per-record instead of per-rmgr.
|
generate statistics per-record instead of per-rmgr.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
If <application>pg_waldump</application> is terminated by signal
|
||||||
|
<systemitem>SIGINT</systemitem>
|
||||||
|
(<keycombo action="simul"><keycap>Control</keycap><keycap>C</keycap></keycombo>,
|
||||||
|
the summary of the statistics computed is displayed up to the
|
||||||
|
termination point. This operation is not supported on
|
||||||
|
<productname>Windows</productname>.
|
||||||
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
@ -28,6 +29,7 @@
|
|||||||
static const char *progname;
|
static const char *progname;
|
||||||
|
|
||||||
static int WalSegSz;
|
static int WalSegSz;
|
||||||
|
static volatile sig_atomic_t time_to_stop = false;
|
||||||
|
|
||||||
typedef struct XLogDumpPrivate
|
typedef struct XLogDumpPrivate
|
||||||
{
|
{
|
||||||
@ -67,12 +69,27 @@ typedef struct Stats
|
|||||||
typedef struct XLogDumpStats
|
typedef struct XLogDumpStats
|
||||||
{
|
{
|
||||||
uint64 count;
|
uint64 count;
|
||||||
|
XLogRecPtr startptr;
|
||||||
|
XLogRecPtr endptr;
|
||||||
Stats rmgr_stats[RM_NEXT_ID];
|
Stats rmgr_stats[RM_NEXT_ID];
|
||||||
Stats record_stats[RM_NEXT_ID][MAX_XLINFO_TYPES];
|
Stats record_stats[RM_NEXT_ID][MAX_XLINFO_TYPES];
|
||||||
} XLogDumpStats;
|
} XLogDumpStats;
|
||||||
|
|
||||||
#define fatal_error(...) do { pg_log_fatal(__VA_ARGS__); exit(EXIT_FAILURE); } while(0)
|
#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
|
static void
|
||||||
print_rmgr_list(void)
|
print_rmgr_list(void)
|
||||||
{
|
{
|
||||||
@ -632,6 +649,12 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats)
|
|||||||
double rec_len_pct,
|
double rec_len_pct,
|
||||||
fpi_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
|
* Each row shows its percentages of the total, so make a first pass to
|
||||||
* calculate column totals.
|
* calculate column totals.
|
||||||
@ -645,6 +668,9 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats)
|
|||||||
}
|
}
|
||||||
total_len = total_rec_len + total_fpi_len;
|
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
|
* 27 is strlen("Transaction/COMMIT_PREPARED"), 20 is strlen(2^64), 8 is
|
||||||
* strlen("(100.00%)")
|
* strlen("(100.00%)")
|
||||||
@ -794,6 +820,10 @@ main(int argc, char **argv)
|
|||||||
int option;
|
int option;
|
||||||
int optindex = 0;
|
int optindex = 0;
|
||||||
|
|
||||||
|
#ifndef WIN32
|
||||||
|
pqsignal(SIGINT, sigint_handler);
|
||||||
|
#endif
|
||||||
|
|
||||||
pg_logging_init(argv[0]);
|
pg_logging_init(argv[0]);
|
||||||
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_waldump"));
|
set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_waldump"));
|
||||||
progname = get_progname(argv[0]);
|
progname = get_progname(argv[0]);
|
||||||
@ -833,6 +863,9 @@ main(int argc, char **argv)
|
|||||||
config.stats = false;
|
config.stats = false;
|
||||||
config.stats_per_record = false;
|
config.stats_per_record = false;
|
||||||
|
|
||||||
|
stats.startptr = InvalidXLogRecPtr;
|
||||||
|
stats.endptr = InvalidXLogRecPtr;
|
||||||
|
|
||||||
if (argc <= 1)
|
if (argc <= 1)
|
||||||
{
|
{
|
||||||
pg_log_error("no arguments specified");
|
pg_log_error("no arguments specified");
|
||||||
@ -1084,8 +1117,17 @@ main(int argc, char **argv)
|
|||||||
LSN_FORMAT_ARGS(first_record),
|
LSN_FORMAT_ARGS(first_record),
|
||||||
(uint32) (first_record - private.startptr));
|
(uint32) (first_record - private.startptr));
|
||||||
|
|
||||||
|
if (config.stats == true && !config.quiet)
|
||||||
|
stats.startptr = first_record;
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
if (time_to_stop)
|
||||||
|
{
|
||||||
|
/* We've been Ctrl-C'ed, so leave */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* try to read the next record */
|
/* try to read the next record */
|
||||||
record = XLogReadRecord(xlogreader_state, &errormsg);
|
record = XLogReadRecord(xlogreader_state, &errormsg);
|
||||||
if (!record)
|
if (!record)
|
||||||
@ -1112,7 +1154,10 @@ main(int argc, char **argv)
|
|||||||
if (!config.quiet)
|
if (!config.quiet)
|
||||||
{
|
{
|
||||||
if (config.stats == true)
|
if (config.stats == true)
|
||||||
|
{
|
||||||
XLogDumpCountRecord(&config, &stats, xlogreader_state);
|
XLogDumpCountRecord(&config, &stats, xlogreader_state);
|
||||||
|
stats.endptr = xlogreader_state->EndRecPtr;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
XLogDumpDisplayRecord(&config, xlogreader_state);
|
XLogDumpDisplayRecord(&config, xlogreader_state);
|
||||||
}
|
}
|
||||||
@ -1127,6 +1172,9 @@ main(int argc, char **argv)
|
|||||||
if (config.stats == true && !config.quiet)
|
if (config.stats == true && !config.quiet)
|
||||||
XLogDumpDisplayStats(&config, &stats);
|
XLogDumpDisplayStats(&config, &stats);
|
||||||
|
|
||||||
|
if (time_to_stop)
|
||||||
|
exit(0);
|
||||||
|
|
||||||
if (errormsg)
|
if (errormsg)
|
||||||
fatal_error("error in WAL record at %X/%X: %s",
|
fatal_error("error in WAL record at %X/%X: %s",
|
||||||
LSN_FORMAT_ARGS(xlogreader_state->ReadRecPtr),
|
LSN_FORMAT_ARGS(xlogreader_state->ReadRecPtr),
|
||||||
|
Loading…
Reference in New Issue
Block a user