full-page images) instead of individual records. Optionally
generate statistics per-record instead of per-rmgr.
</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>
</varlistentry>
#include "postgres.h"
#include <dirent.h>
+#include <signal.h>
#include <sys/stat.h>
#include <unistd.h>
static const char *progname;
static int WalSegSz;
+static volatile sig_atomic_t time_to_stop = false;
typedef struct XLogDumpPrivate
{
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)
{
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.
}
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%)")
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]);
config.stats = false;
config.stats_per_record = false;
+ stats.startptr = InvalidXLogRecPtr;
+ stats.endptr = InvalidXLogRecPtr;
+
if (argc <= 1)
{
pg_log_error("no arguments specified");
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)
if (!config.quiet)
{
if (config.stats == true)
+ {
XLogDumpCountRecord(&config, &stats, xlogreader_state);
+ stats.endptr = xlogreader_state->EndRecPtr;
+ }
else
XLogDumpDisplayRecord(&config, xlogreader_state);
}
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),