pg_xlogdump --stats
Hi.
Here's a patch to make pg_xlogdump print summary statistics instead of
individual records.
By default, for each rmgr it shows the number of records, the size of
rmgr-specific records, the size of full-page images, and the combined
size. With --stats=record it shows these figures for each rmgr/xl_info
combination (omitting those with zero counts for readability).
Here's an example of the output after a few pgbench runs with the
default checkpoint settings. I raised wal_keep_segments, resulting
in 3.5GB of WAL data in pg_xlog.
As you can see in the "Total" line, 96.83% of this is full-page images.
As Andres observed, this is a good demonstration of why one should not
use the default checkpoint_segments in production.
$ ../bin/pg_xlogdump --stats=record 000000010000000000000001 0000000100000000000000DE
Type N (%) Record size (%) FPI size (%) Combined size (%)
---- - --- ----------- --- -------- --- ------------- ---
XLOG/CHECKPOINT_SHUTDOWN 16 ( 0.00) 1152 ( 0.00) 0 ( 0.00) 1152 ( 0.00)
XLOG/CHECKPOINT_ONLINE 80 ( 0.00) 5760 ( 0.01) 0 ( 0.00) 5760 ( 0.00)
XLOG/NEXTOID 12 ( 0.00) 48 ( 0.00) 0 ( 0.00) 48 ( 0.00)
Transaction/COMMIT 71 ( 0.00) 4708 ( 0.00) 0 ( 0.00) 4708 ( 0.00)
Transaction/COMMIT_COMPACT 413956 ( 14.82) 4967472 ( 4.35) 0 ( 0.00) 4967472 ( 0.14)
Storage/CREATE 231 ( 0.01) 3696 ( 0.00) 0 ( 0.00) 3696 ( 0.00)
Storage/TRUNCATE 1 ( 0.00) 16 ( 0.00) 0 ( 0.00) 16 ( 0.00)
CLOG/ZEROPAGE 13 ( 0.00) 52 ( 0.00) 0 ( 0.00) 52 ( 0.00)
Database/CREATE 3 ( 0.00) 48 ( 0.00) 0 ( 0.00) 48 ( 0.00)
RelMap/UPDATE 14 ( 0.00) 7336 ( 0.01) 0 ( 0.00) 7336 ( 0.00)
Heap2/CLEAN 369312 ( 13.22) 10769122 ( 9.43) 2698910088 ( 77.33) 2709679210 ( 75.17)
Heap2/FREEZE_PAGE 53 ( 0.00) 3276 ( 0.00) 327732 ( 0.01) 331008 ( 0.01)
Heap2/VISIBLE 58160 ( 2.08) 1163200 ( 1.02) 599768 ( 0.02) 1762968 ( 0.05)
Heap2/MULTI_INSERT 1 ( 0.00) 59 ( 0.00) 0 ( 0.00) 59 ( 0.00)
Heap2/MULTI_INSERT+INIT 7 ( 0.00) 38874 ( 0.03) 0 ( 0.00) 38874 ( 0.00)
Heap/INSERT 425472 ( 15.23) 22392664 ( 19.61) 6081712 ( 0.17) 28474376 ( 0.79)
Heap/DELETE 1638 ( 0.06) 42588 ( 0.04) 19800 ( 0.00) 62388 ( 0.00)
Heap/UPDATE 53912 ( 1.93) 7145531 ( 6.26) 390264760 ( 11.18) 397410291 ( 11.03)
Heap/HOT_UPDATE 1185607 ( 42.43) 59538947 ( 52.13) 48724168 ( 1.40) 108263115 ( 3.00)
Heap/LOCK 199320 ( 7.13) 4983000 ( 4.36) 1656812 ( 0.05) 6639812 ( 0.18)
Heap/INPLACE 469 ( 0.02) 66676 ( 0.06) 558604 ( 0.02) 625280 ( 0.02)
Heap/INSERT+INIT 2992 ( 0.11) 272895 ( 0.24) 0 ( 0.00) 272895 ( 0.01)
Heap/UPDATE+INIT 1184 ( 0.04) 146420 ( 0.13) 6611352 ( 0.19) 6757772 ( 0.19)
Btree/INSERT_LEAF 81058 ( 2.90) 2224916 ( 1.95) 336444372 ( 9.64) 338669288 ( 9.40)
Btree/INSERT_UPPER 128 ( 0.00) 5272 ( 0.00) 16368 ( 0.00) 21640 ( 0.00)
Btree/SPLIT_L 48 ( 0.00) 171384 ( 0.15) 46712 ( 0.00) 218096 ( 0.01)
Btree/SPLIT_R 80 ( 0.00) 233736 ( 0.20) 39116 ( 0.00) 272852 ( 0.01)
Btree/SPLIT_L_ROOT 7 ( 0.00) 5488 ( 0.00) 0 ( 0.00) 5488 ( 0.00)
Btree/SPLIT_R_ROOT 4 ( 0.00) 2880 ( 0.00) 0 ( 0.00) 2880 ( 0.00)
Btree/DELETE 3 ( 0.00) 454 ( 0.00) 0 ( 0.00) 454 ( 0.00)
Btree/UNLINK_PAGE 4 ( 0.00) 176 ( 0.00) 0 ( 0.00) 176 ( 0.00)
Btree/NEWROOT 33 ( 0.00) 980 ( 0.00) 0 ( 0.00) 980 ( 0.00)
Btree/MARK_PAGE_HALFDEAD 4 ( 0.00) 144 ( 0.00) 0 ( 0.00) 144 ( 0.00)
Btree/VACUUM 66 ( 0.00) 7890 ( 0.01) 18400 ( 0.00) 26290 ( 0.00)
-------- -------- -------- --------
Total 2793959 114206860 [3.17%] 3490319764 [96.83%] 3604526624 [100%]
pg_xlogdump: FATAL: error in WAL record at 0/DEA52150: record with zero length at 0/DEA521B8
(Note: the FATAL error above is just the normal end of WAL.)
In each row,
- Type is rmgr/record
- N is the number of records of that type
- % is the percentage of total records
- Record size is sum(xl_len+SizeOfXLogRecord)
- % is the percentage of the total record size
- FPI size is the size of full-page images
- % is the percentage of the total FPI size
- Combined size is sum(xl_tot_len)
- % is the percentage of the total combined size
The last line ("Total") shows the total number of records of all types,
the total record size (and what percentage that is of the total size),
the total full-page image size (and ditto), and the total combined size
(which is 100% by definition).
The patch is quite straightforward, but became quite long due to the
many switch/cases needed to name each meaningful xl_rmid/xl_info
combination.
I'll add it to the CF.
-- Abhijit
Attachments:
stats.difftext/x-diff; charset=us-asciiDownload
commit 1d687aeea278e0313071c238e6c3dc04e3e8b798
Author: Abhijit Menon-Sen <ams@2ndQuadrant.com>
Date: Wed Jun 4 14:22:33 2014 +0530
Make 'pg_xlogdump --stats[=record]' display summary statistics
diff --git a/contrib/pg_xlogdump/pg_xlogdump.c b/contrib/pg_xlogdump/pg_xlogdump.c
index 824b8c3..ed9dd31 100644
--- a/contrib/pg_xlogdump/pg_xlogdump.c
+++ b/contrib/pg_xlogdump/pg_xlogdump.c
@@ -15,12 +15,28 @@
#include <dirent.h>
#include <unistd.h>
+#include "access/clog.h"
+#include "access/gin_private.h"
+#include "access/gist_private.h"
+#include "access/heapam_xlog.h"
+#include "access/heapam_xlog.h"
+#include "access/multixact.h"
+#include "access/nbtree.h"
+#include "access/spgist_private.h"
+#include "access/xact.h"
#include "access/xlog.h"
#include "access/xlogreader.h"
#include "access/transam.h"
+#include "catalog/pg_control.h"
+#include "catalog/storage_xlog.h"
+#include "commands/dbcommands.h"
+#include "commands/sequence.h"
+#include "commands/tablespace.h"
#include "common/fe_memutils.h"
#include "getopt_long.h"
#include "rmgrdesc.h"
+#include "storage/standby.h"
+#include "utils/relmapper.h"
static const char *progname;
@@ -41,6 +57,8 @@ typedef struct XLogDumpConfig
int stop_after_records;
int already_displayed_records;
bool follow;
+ bool stats;
+ bool stats_per_record;
/* filter options */
int filter_by_rmgr;
@@ -48,6 +66,20 @@ typedef struct XLogDumpConfig
bool filter_by_xid_enabled;
} XLogDumpConfig;
+typedef struct Stats
+{
+ uint64 count;
+ uint64 rec_len;
+ uint64 fpi_len;
+} Stats;
+
+typedef struct XLogDumpStats
+{
+ uint64 count;
+ Stats rmgr_stats[RM_NEXT_ID];
+ Stats record_stats[RM_NEXT_ID][16];
+} XLogDumpStats;
+
static void
fatal_error(const char *fmt,...)
__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
@@ -322,6 +354,50 @@ XLogDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen,
}
/*
+ * Store per-rmgr and per-record statistics for a given record.
+ */
+static void
+XLogDumpCountRecord(XLogDumpConfig *config, XLogDumpStats *stats, XLogRecPtr ReadRecPtr, XLogRecord *record)
+{
+ RmgrId rmid;
+ uint8 recid;
+
+ if (config->filter_by_rmgr != -1 &&
+ config->filter_by_rmgr != record->xl_rmid)
+ return;
+
+ if (config->filter_by_xid_enabled &&
+ config->filter_by_xid != record->xl_xid)
+ return;
+
+ stats->count++;
+
+ /* Update per-rmgr statistics */
+
+ rmid = record->xl_rmid;
+
+ stats->rmgr_stats[rmid].count++;
+ stats->rmgr_stats[rmid].rec_len +=
+ record->xl_len + SizeOfXLogRecord;
+ stats->rmgr_stats[rmid].fpi_len +=
+ record->xl_tot_len - (record->xl_len + SizeOfXLogRecord);
+
+ /*
+ * Update per-record statistics, where the record is identified by a
+ * combination of the RmgrId and the upper four bits of the xl_info
+ * field (to give sixteen possible entries per RmgrId).
+ */
+
+ recid = (record->xl_info & ~XLR_INFO_MASK) >> 4;
+
+ stats->record_stats[rmid][recid].count++;
+ stats->record_stats[rmid][recid].rec_len +=
+ record->xl_len + SizeOfXLogRecord;
+ stats->record_stats[rmid][recid].fpi_len +=
+ record->xl_tot_len - (record->xl_len + SizeOfXLogRecord);
+}
+
+/*
* Print a record to stdout
*/
static void
@@ -380,6 +456,498 @@ XLogDumpDisplayRecord(XLogDumpConfig *config, XLogRecPtr ReadRecPtr, XLogRecord
}
}
+/*
+ * Given an xl_rmid and the high bits of xl_info, returns a string
+ * describing the record type.
+ */
+static const char *
+identify_record(RmgrId rmid, uint8 info)
+{
+ const RmgrDescData *desc = &RmgrDescTable[rmid];
+ const char *rec;
+
+ rec = psprintf("0x%x", info);
+
+ switch (rmid)
+ {
+ case RM_XLOG_ID:
+ switch (info)
+ {
+ case XLOG_CHECKPOINT_SHUTDOWN:
+ rec = "CHECKPOINT_SHUTDOWN";
+ break;
+ case XLOG_CHECKPOINT_ONLINE:
+ rec = "CHECKPOINT_ONLINE";
+ break;
+ case XLOG_NOOP:
+ rec = "NOOP";
+ break;
+ case XLOG_NEXTOID:
+ rec = "NEXTOID";
+ break;
+ case XLOG_SWITCH:
+ rec = "SWITCH";
+ break;
+ case XLOG_BACKUP_END:
+ rec = "BACKUP_END";
+ break;
+ case XLOG_PARAMETER_CHANGE:
+ rec = "PARAMETER_CHANGE";
+ break;
+ case XLOG_RESTORE_POINT:
+ rec = "RESTORE_POINT";
+ break;
+ case XLOG_FPW_CHANGE:
+ rec = "FPW_CHANGE";
+ break;
+ case XLOG_END_OF_RECOVERY:
+ rec = "END_OF_RECOVERY";
+ break;
+ case XLOG_FPI:
+ rec = "FPI";
+ break;
+ }
+ break;
+
+ case RM_XACT_ID:
+ switch (info)
+ {
+ case XLOG_XACT_COMMIT:
+ rec = "COMMIT";
+ break;
+ case XLOG_XACT_PREPARE:
+ rec = "PREPARE";
+ break;
+ case XLOG_XACT_ABORT:
+ rec = "ABORT";
+ break;
+ case XLOG_XACT_COMMIT_PREPARED:
+ rec = "COMMIT_PREPARED";
+ break;
+ case XLOG_XACT_ABORT_PREPARED:
+ rec = "ABORT_PREPARED";
+ break;
+ case XLOG_XACT_ASSIGNMENT:
+ rec = "ASSIGNMENT";
+ break;
+ case XLOG_XACT_COMMIT_COMPACT:
+ rec = "COMMIT_COMPACT";
+ break;
+ }
+ break;
+
+ case RM_SMGR_ID:
+ switch (info)
+ {
+ case XLOG_SMGR_CREATE:
+ rec = "CREATE";
+ break;
+ case XLOG_SMGR_TRUNCATE:
+ rec = "TRUNCATE";
+ break;
+ }
+ break;
+
+ case RM_CLOG_ID:
+ switch (info)
+ {
+ case CLOG_ZEROPAGE:
+ rec = "ZEROPAGE";
+ break;
+ case CLOG_TRUNCATE:
+ rec = "TRUNCATE";
+ break;
+ }
+ break;
+
+ case RM_DBASE_ID:
+ switch (info)
+ {
+ case XLOG_DBASE_CREATE:
+ rec = "CREATE";
+ break;
+ case XLOG_DBASE_DROP:
+ rec = "DROP";
+ break;
+ }
+ break;
+
+ case RM_TBLSPC_ID:
+ switch (info)
+ {
+ case XLOG_TBLSPC_CREATE:
+ rec = "CREATE";
+ break;
+ case XLOG_TBLSPC_DROP:
+ rec = "DROP";
+ break;
+ }
+ break;
+
+ case RM_MULTIXACT_ID:
+ switch (info)
+ {
+ case XLOG_MULTIXACT_ZERO_OFF_PAGE:
+ rec = "ZERO_OFF_PAGE";
+ break;
+ case XLOG_MULTIXACT_ZERO_MEM_PAGE:
+ rec = "ZERO_MEM_PAGE";
+ break;
+ case XLOG_MULTIXACT_CREATE_ID:
+ rec = "CREATE_ID";
+ break;
+ }
+ break;
+
+ case RM_RELMAP_ID:
+ switch (info)
+ {
+ case XLOG_RELMAP_UPDATE:
+ rec = "UPDATE";
+ break;
+ }
+ break;
+
+ case RM_STANDBY_ID:
+ switch (info)
+ {
+ case XLOG_STANDBY_LOCK:
+ rec = "LOCK";
+ break;
+ case XLOG_RUNNING_XACTS:
+ rec = "RUNNING_XACTS";
+ break;
+ }
+ break;
+
+ case RM_HEAP2_ID:
+ switch (info & XLOG_HEAP_OPMASK)
+ {
+ case XLOG_HEAP2_CLEAN:
+ rec = "CLEAN";
+ break;
+ case XLOG_HEAP2_FREEZE_PAGE:
+ rec = "FREEZE_PAGE";
+ break;
+ case XLOG_HEAP2_CLEANUP_INFO:
+ rec = "CLEANUP_INFO";
+ break;
+ case XLOG_HEAP2_VISIBLE:
+ rec = "VISIBLE";
+ break;
+ case XLOG_HEAP2_MULTI_INSERT:
+ rec = "MULTI_INSERT";
+ break;
+ case XLOG_HEAP2_LOCK_UPDATED:
+ rec = "LOCK_UPDATED";
+ break;
+ case XLOG_HEAP2_NEW_CID:
+ rec = "NEW_CID";
+ break;
+ case XLOG_HEAP2_REWRITE:
+ rec = "REWRITE";
+ break;
+ }
+
+ if (info & XLOG_HEAP_INIT_PAGE)
+ rec = psprintf("%s+INIT", rec);
+
+ break;
+
+ case RM_HEAP_ID:
+ switch (info & XLOG_HEAP_OPMASK)
+ {
+ case XLOG_HEAP_INSERT:
+ rec = "INSERT";
+ break;
+ case XLOG_HEAP_DELETE:
+ rec = "DELETE";
+ break;
+ case XLOG_HEAP_UPDATE:
+ rec = "UPDATE";
+ break;
+ case XLOG_HEAP_HOT_UPDATE:
+ rec = "HOT_UPDATE";
+ break;
+ case XLOG_HEAP_NEWPAGE:
+ rec = "NEWPAGE";
+ break;
+ case XLOG_HEAP_LOCK:
+ rec = "LOCK";
+ break;
+ case XLOG_HEAP_INPLACE:
+ rec = "INPLACE";
+ break;
+ }
+
+ if (info & XLOG_HEAP_INIT_PAGE)
+ rec = psprintf("%s+INIT", rec);
+
+ break;
+
+ case RM_BTREE_ID:
+ switch (info)
+ {
+ case XLOG_BTREE_INSERT_LEAF:
+ rec = "INSERT_LEAF";
+ break;
+ case XLOG_BTREE_INSERT_UPPER:
+ rec = "INSERT_UPPER";
+ break;
+ case XLOG_BTREE_INSERT_META:
+ rec = "INSERT_META";
+ break;
+ case XLOG_BTREE_SPLIT_L:
+ rec = "SPLIT_L";
+ break;
+ case XLOG_BTREE_SPLIT_R:
+ rec = "SPLIT_R";
+ break;
+ case XLOG_BTREE_SPLIT_L_ROOT:
+ rec = "SPLIT_L_ROOT";
+ break;
+ case XLOG_BTREE_SPLIT_R_ROOT:
+ rec = "SPLIT_R_ROOT";
+ break;
+ case XLOG_BTREE_VACUUM:
+ rec = "VACUUM";
+ break;
+ case XLOG_BTREE_DELETE:
+ rec = "DELETE";
+ break;
+ case XLOG_BTREE_MARK_PAGE_HALFDEAD:
+ rec = "MARK_PAGE_HALFDEAD";
+ break;
+ case XLOG_BTREE_UNLINK_PAGE:
+ rec = "UNLINK_PAGE";
+ break;
+ case XLOG_BTREE_UNLINK_PAGE_META:
+ rec = "UNLINK_PAGE_META";
+ break;
+ case XLOG_BTREE_NEWROOT:
+ rec = "NEWROOT";
+ break;
+ case XLOG_BTREE_REUSE_PAGE:
+ rec = "REUSE_PAGE";
+ break;
+ }
+ break;
+
+ case RM_HASH_ID:
+ break;
+
+ case RM_GIN_ID:
+ switch (info)
+ {
+ case XLOG_GIN_CREATE_INDEX:
+ rec = "CREATE_INDEX";
+ break;
+ case XLOG_GIN_CREATE_PTREE:
+ rec = "CREATE_PTREE";
+ break;
+ case XLOG_GIN_INSERT:
+ rec = "INSERT";
+ break;
+ case XLOG_GIN_SPLIT:
+ rec = "SPLIT";
+ break;
+ case XLOG_GIN_VACUUM_PAGE:
+ rec = "VACUUM_PAGE";
+ break;
+ case XLOG_GIN_VACUUM_DATA_LEAF_PAGE:
+ rec = "VACUUM_DATA_LEAF_PAGE";
+ break;
+ case XLOG_GIN_DELETE_PAGE:
+ rec = "DELETE_PAGE";
+ break;
+ case XLOG_GIN_UPDATE_META_PAGE:
+ rec = "UPDATE_META_PAGE";
+ break;
+ case XLOG_GIN_INSERT_LISTPAGE:
+ rec = "INSERT_LISTPAGE";
+ break;
+ case XLOG_GIN_DELETE_LISTPAGE:
+ rec = "DELETE_LISTPAGE";
+ break;
+ }
+ break;
+
+ case RM_GIST_ID:
+ switch (info)
+ {
+ case XLOG_GIST_PAGE_UPDATE:
+ rec = "PAGE_UPDATE";
+ break;
+ case XLOG_GIST_PAGE_SPLIT:
+ rec = "PAGE_SPLIT";
+ break;
+ case XLOG_GIST_CREATE_INDEX:
+ rec = "CREATE_INDEX";
+ break;
+ }
+ break;
+
+ case RM_SEQ_ID:
+ switch (info)
+ {
+ case XLOG_SEQ_LOG:
+ rec = "LOG";
+ break;
+ }
+ break;
+
+ case RM_SPGIST_ID:
+ switch (info)
+ {
+ case XLOG_SPGIST_CREATE_INDEX:
+ rec = "CREATE_INDEX";
+ break;
+ case XLOG_SPGIST_ADD_LEAF:
+ rec = "ADD_LEAF";
+ break;
+ case XLOG_SPGIST_MOVE_LEAFS:
+ rec = "MOVE_LEAFS";
+ break;
+ case XLOG_SPGIST_ADD_NODE:
+ rec = "ADD_NODE";
+ break;
+ case XLOG_SPGIST_SPLIT_TUPLE:
+ rec = "SPLIT_TUPLE";
+ break;
+ case XLOG_SPGIST_PICKSPLIT:
+ rec = "PICKSPLIT";
+ break;
+ case XLOG_SPGIST_VACUUM_LEAF:
+ rec = "VACUUM_LEAF";
+ break;
+ case XLOG_SPGIST_VACUUM_ROOT:
+ rec = "VACUUM_ROOT";
+ break;
+ case XLOG_SPGIST_VACUUM_REDIRECT:
+ rec = "VACUUM_REDIRECT";
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return psprintf("%s/%s", desc->rm_name, rec);
+}
+
+/*
+ * Display a single row of record counts and sizes for an rmgr or record.
+ */
+static void
+XLogDumpStatsRow(const char *name,
+ uint64 n, double n_pct,
+ uint64 rec_len, double rec_len_pct,
+ uint64 fpi_len, double fpi_len_pct,
+ uint64 total_len, double total_len_pct)
+{
+ printf("%-27s %20llu (%6.02f) %20llu (%6.02f) %20llu (%6.02f) %20llu (%6.02f)\n",
+ name, n, n_pct, rec_len, rec_len_pct, fpi_len, fpi_len_pct,
+ total_len, total_len_pct);
+}
+
+
+/*
+ * Display summary statistics about the records seen so far.
+ */
+static void
+XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats)
+{
+ int ri, rj;
+ uint64 total_count = 0;
+ uint64 total_rec_len = 0;
+ uint64 total_fpi_len = 0;
+ uint64 total_len = 0;
+
+ /*
+ * Make a first pass to calculate column totals:
+ * count(*),
+ * sum(xl_len+SizeOfXLogRecord),
+ * sum(xl_tot_len-xl_len-SizeOfXLogRecord), and
+ * sum(xl_tot_len).
+ * These are used to calculate percentages for each record type.
+ */
+
+ for (ri = 0; ri < RM_NEXT_ID; ri++)
+ {
+ total_count += stats->rmgr_stats[ri].count;
+ total_rec_len += stats->rmgr_stats[ri].rec_len;
+ total_fpi_len += stats->rmgr_stats[ri].fpi_len;
+ }
+ total_len = total_rec_len+total_fpi_len;
+
+ /*
+ * 27 is strlen("Transaction/COMMIT_PREPARED"),
+ * 20 is strlen(2^64), 8 is strlen("(100.00%)")
+ */
+
+ printf("%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n"
+ "%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n",
+ "Type", "N", "(%)", "Record size", "(%)", "FPI size", "(%)", "Combined size", "(%)",
+ "----", "-", "---", "-----------", "---", "--------", "---", "-------------", "---");
+
+ for (ri = 0; ri < RM_NEXT_ID; ri++)
+ {
+ uint64 count, rec_len, fpi_len;
+
+ if (!config->stats_per_record)
+ {
+ const RmgrDescData *desc = &RmgrDescTable[ri];
+
+ count = stats->rmgr_stats[ri].count;
+ rec_len = stats->rmgr_stats[ri].rec_len;
+ fpi_len = stats->rmgr_stats[ri].fpi_len;
+
+ XLogDumpStatsRow(desc->rm_name,
+ count, 100*(double)count/total_count,
+ rec_len, 100*(double)rec_len/total_rec_len,
+ fpi_len, 100*(double)fpi_len/total_fpi_len,
+ rec_len+fpi_len, 100*(double)(rec_len+fpi_len)/total_len);
+ }
+ else
+ {
+ for (rj = 0; rj < 16; rj++)
+ {
+ count = stats->record_stats[ri][rj].count;
+ rec_len = stats->record_stats[ri][rj].rec_len;
+ fpi_len = stats->record_stats[ri][rj].fpi_len;
+
+ /* Skip undefined combinations and ones that didn't occur */
+ if (count == 0)
+ continue;
+
+ XLogDumpStatsRow(identify_record(ri, rj << 4),
+ count, 100*(double)count/total_count,
+ rec_len, 100*(double)rec_len/total_rec_len,
+ fpi_len, 100*(double)fpi_len/total_fpi_len,
+ rec_len+fpi_len, 100*(double)(rec_len+fpi_len)/total_len);
+ }
+ }
+ }
+
+ printf("%-27s %20s %8s %20s %8s %20s %8s %20s\n",
+ "", "--------", "", "--------", "", "--------", "", "--------");
+
+ /*
+ * The percentages in earlier rows were calculated against the
+ * column total, but the ones that follow are against the row total.
+ * Note that these are displayed with a % symbol to differentiate
+ * them from the earlier ones, and are thus up to 9 characters long.
+ */
+
+ printf("%-27s %20llu %-9s%20llu %-9s%20llu %-9s%20llu %-6s\n",
+ "Total",
+ stats->count, "",
+ total_rec_len, psprintf("[%.02f%%]", 100*(double)total_rec_len/total_len),
+ total_fpi_len, psprintf("[%.02f%%]", 100*(double)total_fpi_len/total_len),
+ total_len, "[100%]");
+}
+
static void
usage(void)
{
@@ -401,6 +969,8 @@ usage(void)
printf(" (default: 1 or the value used in STARTSEG)\n");
printf(" -V, --version output version information, then exit\n");
printf(" -x, --xid=XID only show records with TransactionId XID\n");
+ printf(" -z, --stats[=record] show statistics instead of records\n");
+ printf(" (optionally, show per-record statistics)\n");
printf(" -?, --help show this help, then exit\n");
}
@@ -412,6 +982,7 @@ main(int argc, char **argv)
XLogReaderState *xlogreader_state;
XLogDumpPrivate private;
XLogDumpConfig config;
+ XLogDumpStats stats;
XLogRecord *record;
XLogRecPtr first_record;
char *errormsg;
@@ -428,6 +999,7 @@ main(int argc, char **argv)
{"timeline", required_argument, NULL, 't'},
{"xid", required_argument, NULL, 'x'},
{"version", no_argument, NULL, 'V'},
+ {"stats", optional_argument, NULL, 'z'},
{NULL, 0, NULL, 0}
};
@@ -438,6 +1010,7 @@ main(int argc, char **argv)
memset(&private, 0, sizeof(XLogDumpPrivate));
memset(&config, 0, sizeof(XLogDumpConfig));
+ memset(&stats, 0, sizeof(XLogDumpStats));
private.timeline = 1;
private.startptr = InvalidXLogRecPtr;
@@ -451,6 +1024,8 @@ main(int argc, char **argv)
config.filter_by_rmgr = -1;
config.filter_by_xid = InvalidTransactionId;
config.filter_by_xid_enabled = false;
+ config.stats = false;
+ config.stats_per_record = false;
if (argc <= 1)
{
@@ -458,7 +1033,7 @@ main(int argc, char **argv)
goto bad_argument;
}
- while ((option = getopt_long(argc, argv, "be:?fn:p:r:s:t:Vx:",
+ while ((option = getopt_long(argc, argv, "be:?fn:p:r:s:t:Vx:z::",
long_options, &optindex)) != -1)
{
switch (option)
@@ -551,6 +1126,20 @@ main(int argc, char **argv)
}
config.filter_by_xid_enabled = true;
break;
+ case 'z':
+ config.stats = true;
+ if (optarg)
+ {
+ if (strcmp(optarg, "record") == 0)
+ config.stats_per_record = true;
+ else
+ {
+ fprintf(stderr, "%s: unrecognised argument to --stats: %s\n",
+ progname, optarg);
+ goto bad_argument;
+ }
+ }
+ break;
default:
goto bad_argument;
}
@@ -711,7 +1300,10 @@ main(int argc, char **argv)
/* after reading the first record, continue at next one */
first_record = InvalidXLogRecPtr;
- XLogDumpDisplayRecord(&config, xlogreader_state->ReadRecPtr, record);
+ if (config.stats == true)
+ XLogDumpCountRecord(&config, &stats, xlogreader_state->ReadRecPtr, record);
+ else
+ XLogDumpDisplayRecord(&config, xlogreader_state->ReadRecPtr, record);
/* check whether we printed enough */
if (config.stop_after_records > 0 &&
@@ -719,6 +1311,9 @@ main(int argc, char **argv)
break;
}
+ if (config.stats == true)
+ XLogDumpDisplayStats(&config, &stats);
+
if (errormsg)
fatal_error("error in WAL record at %X/%X: %s\n",
(uint32) (xlogreader_state->ReadRecPtr >> 32),
diff --git a/doc/src/sgml/pg_xlogdump.sgml b/doc/src/sgml/pg_xlogdump.sgml
index 1d1a2ce..d9f4a6a 100644
--- a/doc/src/sgml/pg_xlogdump.sgml
+++ b/doc/src/sgml/pg_xlogdump.sgml
@@ -180,6 +180,18 @@ PostgreSQL documentation
</varlistentry>
<varlistentry>
+ <term><option>-z</option></term>
+ <term><option>--stats[=record]</option></term>
+ <listitem>
+ <para>
+ Display summary statistics (number and size of records and
+ full-page images) instead of individual records. Optionally
+ generate statistics per-record instead of per-rmgr.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-?</></term>
<term><option>--help</></term>
<listitem>
-----Original Message-----
From: pgsql-hackers-owner@postgresql.org
[mailto:pgsql-hackers-owner@postgresql.org] On Behalf Of Abhijit
Menon-Sen
Sent: Wednesday, June 04, 2014 7:47 PM
To: pgsql-hackers@postgresql.org
Subject: [HACKERS] pg_xlogdump --statsHi.
Here's a patch to make pg_xlogdump print summary statistics instead of
individual records.
The function works fine. It is a good to the learning of PostgreSQL.
But By applying the patch,warning comes out then make.
Although I think that's no particular problem, However I think better to fix is good.
$ make
...
pg_xlogdump.c: In function ‘XLogDumpStatsRow’:
pg_xlogdump.c:851: warning: format ‘%20llu’ expects type ‘long long unsigned int’, but argument 3 has type ‘uint64’
pg_xlogdump.c:851: warning: format ‘%20llu’ expects type ‘long long unsigned int’, but argument 5 has type ‘uint64’
pg_xlogdump.c:851: warning: format ‘%20llu’ expects type ‘long long unsigned int’, but argument 7 has type ‘uint64’
pg_xlogdump.c:851: warning: format ‘%20llu’ expects type ‘long long unsigned int’, but argument 9 has type ‘uint64’
pg_xlogdump.c: In function ‘XLogDumpDisplayStats’:
pg_xlogdump.c:948: warning: format ‘%20llu’ expects type ‘long long unsigned int’, but argument 3 has type ‘uint64’
pg_xlogdump.c:948: warning: format ‘%20llu’ expects type ‘long long unsigned int’, but argument 5 has type ‘uint64’
pg_xlogdump.c:948: warning: format ‘%20llu’ expects type ‘long long unsigned int’, but argument 7 has type ‘uint64’
pg_xlogdump.c:948: warning: format ‘%20llu’ expects type ‘long long unsigned int’, but argument 9 has type ‘uint64'
...
My environment:
RHEL 6.4
gcc version 4.4.7 20120313 (Red Hat 4.4.7-3) (GCC)
Regards,
--
Furuya Osamu
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
At 2014-06-10 18:04:13 +0900, furuyao@pm.nttdata.co.jp wrote:
The function works fine. It is a good to the learning of PostgreSQL.
Thanks for having a look.
pg_xlogdump.c: In function ‘XLogDumpStatsRow’:
pg_xlogdump.c:851: warning: format ‘%20llu’ expects type ‘long long unsigned int’, but argument 3 has type ‘uint64’
I've changed this to use %zu at Álvaro's suggestion. I'll post an
updated patch after I've finished some (unrelated) refactoring.
-- Abhijit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 13 June 2014 13:01, Abhijit Menon-Sen Wrote
I've changed this to use %zu at Álvaro's suggestion. I'll post an
updated patch after I've finished some (unrelated) refactoring.
I have started reviewing the patch..
1. Patch applied to git head cleanly.
2. Compiled in Linux -- Some warnings same as mentioned by furuyao
3. Some compilation error in windows
.\contrib\pg_xlogdump\pg_xlogdump.c(1002) : error C2065: 'optional_argument' : undeclared identifier
.\contrib\pg_xlogdump\pg_xlogdump.c(1002) : error C2099: initializer is not a constant
optional_argument should be added to getopt_long.h file for windows.
Please fix these issues and send the updated patch..
I will continue reviewing the patch..
Regards,
Dilip
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
At 2014-06-30 05:19:10 +0000, dilip.kumar@huawei.com wrote:
I have started reviewing the patch..
Thanks.
1. Patch applied to git head cleanly.
2. Compiled in Linux -- Some warnings same as mentioned by furuyao
I've attached an updated version of the patch which should fix the
warnings by using %zu.
3. Some compilation error in windows
.\contrib\pg_xlogdump\pg_xlogdump.c(1002) : error C2065: 'optional_argument' : undeclared identifier
.\contrib\pg_xlogdump\pg_xlogdump.c(1002) : error C2099: initializer is not a constantoptional_argument should be added to getopt_long.h file for windows.
Hmm. I have no idea what to do about this. I did notice when I wrote the
code that nothing else used optional_argument, but I didn't realise that
it wouldn't work on Windows.
It may be that the best thing to do would be to avoid using
optional_argument altogether, and have separate --stats and
--stats-per-record options. Thoughts?
Please fix these issues and send the updated patch..
I've also attached a separate patch to factor out the identify_record
function into rm_identify functions in the individual rmgr files, so
that the code can live next to the respective _desc functions.
This allows us to remove a number of #includes from pg_xlogdump, and
makes the code a bit more straightforward to read.
-- Abhijit
Attachments:
stats2.difftext/x-diff; charset=us-asciiDownload
diff --git a/contrib/pg_xlogdump/pg_xlogdump.c b/contrib/pg_xlogdump/pg_xlogdump.c
index 824b8c3..1d3e664 100644
--- a/contrib/pg_xlogdump/pg_xlogdump.c
+++ b/contrib/pg_xlogdump/pg_xlogdump.c
@@ -15,12 +15,28 @@
#include <dirent.h>
#include <unistd.h>
+#include "access/clog.h"
+#include "access/gin_private.h"
+#include "access/gist_private.h"
+#include "access/heapam_xlog.h"
+#include "access/heapam_xlog.h"
+#include "access/multixact.h"
+#include "access/nbtree.h"
+#include "access/spgist_private.h"
+#include "access/xact.h"
#include "access/xlog.h"
#include "access/xlogreader.h"
#include "access/transam.h"
+#include "catalog/pg_control.h"
+#include "catalog/storage_xlog.h"
+#include "commands/dbcommands.h"
+#include "commands/sequence.h"
+#include "commands/tablespace.h"
#include "common/fe_memutils.h"
#include "getopt_long.h"
#include "rmgrdesc.h"
+#include "storage/standby.h"
+#include "utils/relmapper.h"
static const char *progname;
@@ -41,6 +57,8 @@ typedef struct XLogDumpConfig
int stop_after_records;
int already_displayed_records;
bool follow;
+ bool stats;
+ bool stats_per_record;
/* filter options */
int filter_by_rmgr;
@@ -48,6 +66,20 @@ typedef struct XLogDumpConfig
bool filter_by_xid_enabled;
} XLogDumpConfig;
+typedef struct Stats
+{
+ uint64 count;
+ uint64 rec_len;
+ uint64 fpi_len;
+} Stats;
+
+typedef struct XLogDumpStats
+{
+ uint64 count;
+ Stats rmgr_stats[RM_NEXT_ID];
+ Stats record_stats[RM_NEXT_ID][16];
+} XLogDumpStats;
+
static void
fatal_error(const char *fmt,...)
__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
@@ -322,6 +354,39 @@ XLogDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen,
}
/*
+ * Store per-rmgr and per-record statistics for a given record.
+ */
+static void
+XLogDumpCountRecord(XLogDumpConfig *config, XLogDumpStats *stats, XLogRecPtr ReadRecPtr, XLogRecord *record)
+{
+ RmgrId rmid;
+ uint8 recid;
+
+ if (config->filter_by_rmgr != -1 &&
+ config->filter_by_rmgr != record->xl_rmid)
+ return;
+
+ if (config->filter_by_xid_enabled &&
+ config->filter_by_xid != record->xl_xid)
+ return;
+
+ rmid = record->xl_rmid;
+ recid = (record->xl_info & ~XLR_INFO_MASK) >> 4;
+
+ stats->count++;
+
+ stats->rmgr_stats[rmid].count++;
+ stats->rmgr_stats[rmid].rec_len += record->xl_len;
+ stats->rmgr_stats[rmid].fpi_len +=
+ (record->xl_tot_len - record->xl_len - SizeOfXLogRecord);
+
+ stats->record_stats[rmid][recid].count++;
+ stats->record_stats[rmid][recid].rec_len += record->xl_len;
+ stats->record_stats[rmid][recid].fpi_len +=
+ (record->xl_tot_len - record->xl_len - SizeOfXLogRecord);
+}
+
+/*
* Print a record to stdout
*/
static void
@@ -380,6 +445,476 @@ XLogDumpDisplayRecord(XLogDumpConfig *config, XLogRecPtr ReadRecPtr, XLogRecord
}
}
+/*
+ * Given an xl_rmid and the high bits of xl_info, returns a string
+ * describing the record type.
+ */
+static const char *
+identify_record(RmgrId rmid, uint8 info)
+{
+ const RmgrDescData *desc = &RmgrDescTable[rmid];
+ const char *rec;
+
+ rec = psprintf("0x%x", info);
+
+ switch (rmid)
+ {
+ case RM_XLOG_ID:
+ switch (info)
+ {
+ case XLOG_CHECKPOINT_SHUTDOWN:
+ rec = "CHECKPOINT_SHUTDOWN";
+ break;
+ case XLOG_CHECKPOINT_ONLINE:
+ rec = "CHECKPOINT_ONLINE";
+ break;
+ case XLOG_NOOP:
+ rec = "NOOP";
+ break;
+ case XLOG_NEXTOID:
+ rec = "NEXTOID";
+ break;
+ case XLOG_SWITCH:
+ rec = "SWITCH";
+ break;
+ case XLOG_BACKUP_END:
+ rec = "BACKUP_END";
+ break;
+ case XLOG_PARAMETER_CHANGE:
+ rec = "PARAMETER_CHANGE";
+ break;
+ case XLOG_RESTORE_POINT:
+ rec = "RESTORE_POINT";
+ break;
+ case XLOG_FPW_CHANGE:
+ rec = "FPW_CHANGE";
+ break;
+ case XLOG_END_OF_RECOVERY:
+ rec = "END_OF_RECOVERY";
+ break;
+ case XLOG_FPI:
+ rec = "FPI";
+ break;
+ }
+ break;
+
+ case RM_XACT_ID:
+ switch (info)
+ {
+ case XLOG_XACT_COMMIT:
+ rec = "COMMIT";
+ break;
+ case XLOG_XACT_PREPARE:
+ rec = "PREPARE";
+ break;
+ case XLOG_XACT_ABORT:
+ rec = "ABORT";
+ break;
+ case XLOG_XACT_COMMIT_PREPARED:
+ rec = "COMMIT_PREPARED";
+ break;
+ case XLOG_XACT_ABORT_PREPARED:
+ rec = "ABORT_PREPARED";
+ break;
+ case XLOG_XACT_ASSIGNMENT:
+ rec = "ASSIGNMENT";
+ break;
+ case XLOG_XACT_COMMIT_COMPACT:
+ rec = "COMMIT_COMPACT";
+ break;
+ }
+ break;
+
+ case RM_SMGR_ID:
+ switch (info)
+ {
+ case XLOG_SMGR_CREATE:
+ rec = "CREATE";
+ break;
+ case XLOG_SMGR_TRUNCATE:
+ rec = "TRUNCATE";
+ break;
+ }
+ break;
+
+ case RM_CLOG_ID:
+ switch (info)
+ {
+ case CLOG_ZEROPAGE:
+ rec = "ZEROPAGE";
+ break;
+ case CLOG_TRUNCATE:
+ rec = "TRUNCATE";
+ break;
+ }
+ break;
+
+ case RM_DBASE_ID:
+ switch (info)
+ {
+ case XLOG_DBASE_CREATE:
+ rec = "CREATE";
+ break;
+ case XLOG_DBASE_DROP:
+ rec = "DROP";
+ break;
+ }
+ break;
+
+ case RM_TBLSPC_ID:
+ switch (info)
+ {
+ case XLOG_TBLSPC_CREATE:
+ rec = "CREATE";
+ break;
+ case XLOG_TBLSPC_DROP:
+ rec = "DROP";
+ break;
+ }
+ break;
+
+ case RM_MULTIXACT_ID:
+ switch (info)
+ {
+ case XLOG_MULTIXACT_ZERO_OFF_PAGE:
+ rec = "ZERO_OFF_PAGE";
+ break;
+ case XLOG_MULTIXACT_ZERO_MEM_PAGE:
+ rec = "ZERO_MEM_PAGE";
+ break;
+ case XLOG_MULTIXACT_CREATE_ID:
+ rec = "CREATE_ID";
+ break;
+ }
+ break;
+
+ case RM_RELMAP_ID:
+ switch (info)
+ {
+ case XLOG_RELMAP_UPDATE:
+ rec = "UPDATE";
+ break;
+ }
+ break;
+
+ case RM_STANDBY_ID:
+ switch (info)
+ {
+ case XLOG_STANDBY_LOCK:
+ rec = "LOCK";
+ break;
+ case XLOG_RUNNING_XACTS:
+ rec = "RUNNING_XACTS";
+ break;
+ }
+ break;
+
+ case RM_HEAP2_ID:
+ switch (info & XLOG_HEAP_OPMASK)
+ {
+ case XLOG_HEAP2_CLEAN:
+ rec = "CLEAN";
+ break;
+ case XLOG_HEAP2_FREEZE_PAGE:
+ rec = "FREEZE_PAGE";
+ break;
+ case XLOG_HEAP2_CLEANUP_INFO:
+ rec = "CLEANUP_INFO";
+ break;
+ case XLOG_HEAP2_VISIBLE:
+ rec = "VISIBLE";
+ break;
+ case XLOG_HEAP2_MULTI_INSERT:
+ rec = "MULTI_INSERT";
+ break;
+ case XLOG_HEAP2_LOCK_UPDATED:
+ rec = "LOCK_UPDATED";
+ break;
+ case XLOG_HEAP2_NEW_CID:
+ rec = "NEW_CID";
+ break;
+ case XLOG_HEAP2_REWRITE:
+ rec = "REWRITE";
+ break;
+ }
+ break;
+
+ case RM_HEAP_ID:
+ {
+ /* Top bit is XLOG_HEAP_INIT_PAGE, the remaining three bits
+ * are the opcode. */
+
+ switch (info & XLOG_HEAP_OPMASK)
+ {
+ case XLOG_HEAP_INSERT:
+ rec = "INSERT";
+ break;
+ case XLOG_HEAP_DELETE:
+ rec = "DELETE";
+ break;
+ case XLOG_HEAP_UPDATE:
+ rec = "UPDATE";
+ break;
+ case XLOG_HEAP_HOT_UPDATE:
+ rec = "HOT_UPDATE";
+ break;
+ case XLOG_HEAP_NEWPAGE:
+ rec = "NEWPAGE";
+ break;
+ case XLOG_HEAP_LOCK:
+ rec = "LOCK";
+ break;
+ case XLOG_HEAP_INPLACE:
+ rec = "INPLACE";
+ break;
+ }
+
+ if (info & XLOG_HEAP_INIT_PAGE)
+ rec = psprintf("INIT+%s", rec);
+ }
+ break;
+
+ case RM_BTREE_ID:
+ switch (info)
+ {
+ case XLOG_BTREE_INSERT_LEAF:
+ rec = "INSERT_LEAF";
+ break;
+ case XLOG_BTREE_INSERT_UPPER:
+ rec = "INSERT_UPPER";
+ break;
+ case XLOG_BTREE_INSERT_META:
+ rec = "INSERT_META";
+ break;
+ case XLOG_BTREE_SPLIT_L:
+ rec = "SPLIT_L";
+ break;
+ case XLOG_BTREE_SPLIT_R:
+ rec = "SPLIT_R";
+ break;
+ case XLOG_BTREE_SPLIT_L_ROOT:
+ rec = "SPLIT_L_ROOT";
+ break;
+ case XLOG_BTREE_SPLIT_R_ROOT:
+ rec = "SPLIT_R_ROOT";
+ break;
+ case XLOG_BTREE_VACUUM:
+ rec = "VACUUM";
+ break;
+ case XLOG_BTREE_DELETE:
+ rec = "DELETE";
+ break;
+ case XLOG_BTREE_MARK_PAGE_HALFDEAD:
+ rec = "MARK_PAGE_HALFDEAD";
+ break;
+ case XLOG_BTREE_UNLINK_PAGE:
+ rec = "UNLINK_PAGE";
+ break;
+ case XLOG_BTREE_UNLINK_PAGE_META:
+ rec = "UNLINK_PAGE_META";
+ break;
+ case XLOG_BTREE_NEWROOT:
+ rec = "NEWROOT";
+ break;
+ case XLOG_BTREE_REUSE_PAGE:
+ rec = "REUSE_PAGE";
+ break;
+ }
+ break;
+
+ case RM_HASH_ID:
+ break;
+
+ case RM_GIN_ID:
+ switch (info)
+ {
+ case XLOG_GIN_CREATE_INDEX:
+ rec = "CREATE_INDEX";
+ break;
+ case XLOG_GIN_CREATE_PTREE:
+ rec = "CREATE_PTREE";
+ break;
+ case XLOG_GIN_INSERT:
+ rec = "INSERT";
+ break;
+ case XLOG_GIN_SPLIT:
+ rec = "SPLIT";
+ break;
+ case XLOG_GIN_VACUUM_PAGE:
+ rec = "VACUUM_PAGE";
+ break;
+ case XLOG_GIN_VACUUM_DATA_LEAF_PAGE:
+ rec = "VACUUM_DATA_LEAF_PAGE";
+ break;
+ case XLOG_GIN_DELETE_PAGE:
+ rec = "DELETE_PAGE";
+ break;
+ case XLOG_GIN_UPDATE_META_PAGE:
+ rec = "UPDATE_META_PAGE";
+ break;
+ case XLOG_GIN_INSERT_LISTPAGE:
+ rec = "INSERT_LISTPAGE";
+ break;
+ case XLOG_GIN_DELETE_LISTPAGE:
+ rec = "DELETE_LISTPAGE";
+ break;
+ }
+ break;
+
+ case RM_GIST_ID:
+ switch (info)
+ {
+ case XLOG_GIST_PAGE_UPDATE:
+ rec = "PAGE_UPDATE";
+ break;
+ case XLOG_GIST_PAGE_SPLIT:
+ rec = "PAGE_SPLIT";
+ break;
+ case XLOG_GIST_CREATE_INDEX:
+ rec = "CREATE_INDEX";
+ break;
+ }
+ break;
+
+ case RM_SEQ_ID:
+ switch (info)
+ {
+ case XLOG_SEQ_LOG:
+ rec = "LOG";
+ break;
+ }
+ break;
+
+ case RM_SPGIST_ID:
+ switch (info)
+ {
+ case XLOG_SPGIST_CREATE_INDEX:
+ rec = "CREATE_INDEX";
+ break;
+ case XLOG_SPGIST_ADD_LEAF:
+ rec = "ADD_LEAF";
+ break;
+ case XLOG_SPGIST_MOVE_LEAFS:
+ rec = "MOVE_LEAFS";
+ break;
+ case XLOG_SPGIST_ADD_NODE:
+ rec = "ADD_NODE";
+ break;
+ case XLOG_SPGIST_SPLIT_TUPLE:
+ rec = "SPLIT_TUPLE";
+ break;
+ case XLOG_SPGIST_PICKSPLIT:
+ rec = "PICKSPLIT";
+ break;
+ case XLOG_SPGIST_VACUUM_LEAF:
+ rec = "VACUUM_LEAF";
+ break;
+ case XLOG_SPGIST_VACUUM_ROOT:
+ rec = "VACUUM_ROOT";
+ break;
+ case XLOG_SPGIST_VACUUM_REDIRECT:
+ rec = "VACUUM_REDIRECT";
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return psprintf("%s/%s", desc->rm_name, rec);
+}
+
+/*
+ * Display a single row of record counts and sizes for an rmgr or record.
+ */
+static void
+XLogDumpStatsRow(const char *name,
+ uint64 n, double n_pct,
+ uint64 rec_len, double rec_len_pct,
+ uint64 fpi_len, double fpi_len_pct,
+ uint64 total_len, double total_len_pct)
+{
+ printf("%-27s %20llu (%6.02f) %20llu (%6.02f) %20llu (%6.02f) %20llu (%6.02f)\n",
+ name, n, n_pct, rec_len, rec_len_pct, fpi_len, fpi_len_pct,
+ total_len, total_len_pct);
+}
+
+
+/*
+ * Display summary statistics about the records seen so far.
+ */
+static void
+XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats)
+{
+ int ri, rj;
+ uint64 total_count = 0;
+ uint64 total_rec_len = 0;
+ uint64 total_fpi_len = 0;
+ uint64 total_len = 0;
+
+ for (ri = 0; ri < RM_NEXT_ID; ri++)
+ {
+ total_count += stats->rmgr_stats[ri].count;
+ total_rec_len += stats->rmgr_stats[ri].rec_len;
+ total_fpi_len += stats->rmgr_stats[ri].fpi_len;
+ }
+ total_len = total_rec_len+total_fpi_len;
+
+ printf("%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n"
+ "%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n",
+ "Type", "N", "(%)", "Record size", "(%)", "FPI size", "(%)", "Combined size", "(%)",
+ "----", "-", "---", "-----------", "---", "--------", "---", "-------------", "---");
+
+ for (ri = 0; ri < RM_NEXT_ID; ri++)
+ {
+ uint64 count, rec_len, fpi_len;
+
+ if (!config->stats_per_record)
+ {
+ const RmgrDescData *desc = &RmgrDescTable[ri];
+
+ count = stats->rmgr_stats[ri].count;
+ rec_len = stats->rmgr_stats[ri].rec_len;
+ fpi_len = stats->rmgr_stats[ri].fpi_len;
+
+ XLogDumpStatsRow(desc->rm_name,
+ count, 100*(double)count/total_count,
+ rec_len, 100*(double)rec_len/total_rec_len,
+ fpi_len, 100*(double)fpi_len/total_fpi_len,
+ rec_len+fpi_len, 100*(double)(rec_len+fpi_len)/total_len);
+ }
+ else
+ {
+ for (rj = 0; rj < 16; rj++)
+ {
+ count = stats->record_stats[ri][rj].count;
+ rec_len = stats->record_stats[ri][rj].rec_len;
+ fpi_len = stats->record_stats[ri][rj].fpi_len;
+
+ if (count == 0)
+ continue;
+
+ XLogDumpStatsRow(identify_record(ri, rj << 4),
+ count, 100*(double)count/total_count,
+ rec_len, 100*(double)rec_len/total_rec_len,
+ fpi_len, 100*(double)fpi_len/total_fpi_len,
+ rec_len+fpi_len, 100*(double)(rec_len+fpi_len)/total_len);
+ }
+ }
+ }
+
+ printf("%-27s %20s %8s %20s %8s %20s %8s %20s\n",
+ "", "--------", "", "--------", "", "--------", "", "--------");
+
+ printf("%-27s %20llu %-9s%20llu %-9s%20llu %-9s%20llu %-6s\n",
+ "Total",
+ stats->count, "",
+ total_rec_len, psprintf("[%.02f%%]", 100*(double)total_rec_len/total_len),
+ total_fpi_len, psprintf("[%.02f%%]", 100*(double)total_fpi_len/total_len),
+ total_len, "[100%]");
+}
+
static void
usage(void)
{
@@ -401,6 +936,8 @@ usage(void)
printf(" (default: 1 or the value used in STARTSEG)\n");
printf(" -V, --version output version information, then exit\n");
printf(" -x, --xid=XID only show records with TransactionId XID\n");
+ printf(" -z, --stats[=record] show statistics instead of records\n");
+ printf(" (optionally, show per-record statistics)\n");
printf(" -?, --help show this help, then exit\n");
}
@@ -412,6 +949,7 @@ main(int argc, char **argv)
XLogReaderState *xlogreader_state;
XLogDumpPrivate private;
XLogDumpConfig config;
+ XLogDumpStats stats;
XLogRecord *record;
XLogRecPtr first_record;
char *errormsg;
@@ -428,6 +966,7 @@ main(int argc, char **argv)
{"timeline", required_argument, NULL, 't'},
{"xid", required_argument, NULL, 'x'},
{"version", no_argument, NULL, 'V'},
+ {"stats", optional_argument, NULL, 'z'},
{NULL, 0, NULL, 0}
};
@@ -438,6 +977,7 @@ main(int argc, char **argv)
memset(&private, 0, sizeof(XLogDumpPrivate));
memset(&config, 0, sizeof(XLogDumpConfig));
+ memset(&stats, 0, sizeof(XLogDumpStats));
private.timeline = 1;
private.startptr = InvalidXLogRecPtr;
@@ -451,6 +991,8 @@ main(int argc, char **argv)
config.filter_by_rmgr = -1;
config.filter_by_xid = InvalidTransactionId;
config.filter_by_xid_enabled = false;
+ config.stats = false;
+ config.stats_per_record = false;
if (argc <= 1)
{
@@ -458,7 +1000,7 @@ main(int argc, char **argv)
goto bad_argument;
}
- while ((option = getopt_long(argc, argv, "be:?fn:p:r:s:t:Vx:",
+ while ((option = getopt_long(argc, argv, "be:?fn:p:r:s:t:Vx:z::",
long_options, &optindex)) != -1)
{
switch (option)
@@ -551,6 +1093,20 @@ main(int argc, char **argv)
}
config.filter_by_xid_enabled = true;
break;
+ case 'z':
+ config.stats = true;
+ if (optarg)
+ {
+ if (strcmp(optarg, "record") == 0)
+ config.stats_per_record = true;
+ else
+ {
+ fprintf(stderr, "%s: unrecognised argument to --stats: %s\n",
+ progname, optarg);
+ goto bad_argument;
+ }
+ }
+ break;
default:
goto bad_argument;
}
@@ -711,7 +1267,10 @@ main(int argc, char **argv)
/* after reading the first record, continue at next one */
first_record = InvalidXLogRecPtr;
- XLogDumpDisplayRecord(&config, xlogreader_state->ReadRecPtr, record);
+ if (config.stats == true)
+ XLogDumpCountRecord(&config, &stats, xlogreader_state->ReadRecPtr, record);
+ else
+ XLogDumpDisplayRecord(&config, xlogreader_state->ReadRecPtr, record);
/* check whether we printed enough */
if (config.stop_after_records > 0 &&
@@ -719,6 +1278,9 @@ main(int argc, char **argv)
break;
}
+ if (config.stats == true)
+ XLogDumpDisplayStats(&config, &stats);
+
if (errormsg)
fatal_error("error in WAL record at %X/%X: %s\n",
(uint32) (xlogreader_state->ReadRecPtr >> 32),
rmid.difftext/x-diff; charset=us-asciiDownload
diff --git a/contrib/pg_xlogdump/pg_xlogdump.c b/contrib/pg_xlogdump/pg_xlogdump.c
index 03dfd51..47838d4 100644
--- a/contrib/pg_xlogdump/pg_xlogdump.c
+++ b/contrib/pg_xlogdump/pg_xlogdump.c
@@ -15,28 +15,13 @@
#include <dirent.h>
#include <unistd.h>
-#include "access/clog.h"
-#include "access/gin_private.h"
-#include "access/gist_private.h"
-#include "access/heapam_xlog.h"
-#include "access/heapam_xlog.h"
-#include "access/multixact.h"
-#include "access/nbtree.h"
-#include "access/spgist_private.h"
-#include "access/xact.h"
-#include "access/xlog.h"
#include "access/xlogreader.h"
#include "access/transam.h"
#include "catalog/pg_control.h"
#include "catalog/storage_xlog.h"
-#include "commands/dbcommands.h"
-#include "commands/sequence.h"
-#include "commands/tablespace.h"
#include "common/fe_memutils.h"
#include "getopt_long.h"
#include "rmgrdesc.h"
-#include "storage/standby.h"
-#include "utils/relmapper.h"
static const char *progname;
@@ -457,386 +442,6 @@ XLogDumpDisplayRecord(XLogDumpConfig *config, XLogRecPtr ReadRecPtr, XLogRecord
}
/*
- * Given an xl_rmid and the high bits of xl_info, returns a string
- * describing the record type.
- */
-static const char *
-identify_record(RmgrId rmid, uint8 info)
-{
- const RmgrDescData *desc = &RmgrDescTable[rmid];
- const char *rec;
-
- rec = psprintf("0x%x", info);
-
- switch (rmid)
- {
- case RM_XLOG_ID:
- switch (info)
- {
- case XLOG_CHECKPOINT_SHUTDOWN:
- rec = "CHECKPOINT_SHUTDOWN";
- break;
- case XLOG_CHECKPOINT_ONLINE:
- rec = "CHECKPOINT_ONLINE";
- break;
- case XLOG_NOOP:
- rec = "NOOP";
- break;
- case XLOG_NEXTOID:
- rec = "NEXTOID";
- break;
- case XLOG_SWITCH:
- rec = "SWITCH";
- break;
- case XLOG_BACKUP_END:
- rec = "BACKUP_END";
- break;
- case XLOG_PARAMETER_CHANGE:
- rec = "PARAMETER_CHANGE";
- break;
- case XLOG_RESTORE_POINT:
- rec = "RESTORE_POINT";
- break;
- case XLOG_FPW_CHANGE:
- rec = "FPW_CHANGE";
- break;
- case XLOG_END_OF_RECOVERY:
- rec = "END_OF_RECOVERY";
- break;
- case XLOG_FPI:
- rec = "FPI";
- break;
- }
- break;
-
- case RM_XACT_ID:
- switch (info)
- {
- case XLOG_XACT_COMMIT:
- rec = "COMMIT";
- break;
- case XLOG_XACT_PREPARE:
- rec = "PREPARE";
- break;
- case XLOG_XACT_ABORT:
- rec = "ABORT";
- break;
- case XLOG_XACT_COMMIT_PREPARED:
- rec = "COMMIT_PREPARED";
- break;
- case XLOG_XACT_ABORT_PREPARED:
- rec = "ABORT_PREPARED";
- break;
- case XLOG_XACT_ASSIGNMENT:
- rec = "ASSIGNMENT";
- break;
- case XLOG_XACT_COMMIT_COMPACT:
- rec = "COMMIT_COMPACT";
- break;
- }
- break;
-
- case RM_SMGR_ID:
- switch (info)
- {
- case XLOG_SMGR_CREATE:
- rec = "CREATE";
- break;
- case XLOG_SMGR_TRUNCATE:
- rec = "TRUNCATE";
- break;
- }
- break;
-
- case RM_CLOG_ID:
- switch (info)
- {
- case CLOG_ZEROPAGE:
- rec = "ZEROPAGE";
- break;
- case CLOG_TRUNCATE:
- rec = "TRUNCATE";
- break;
- }
- break;
-
- case RM_DBASE_ID:
- switch (info)
- {
- case XLOG_DBASE_CREATE:
- rec = "CREATE";
- break;
- case XLOG_DBASE_DROP:
- rec = "DROP";
- break;
- }
- break;
-
- case RM_TBLSPC_ID:
- switch (info)
- {
- case XLOG_TBLSPC_CREATE:
- rec = "CREATE";
- break;
- case XLOG_TBLSPC_DROP:
- rec = "DROP";
- break;
- }
- break;
-
- case RM_MULTIXACT_ID:
- switch (info)
- {
- case XLOG_MULTIXACT_ZERO_OFF_PAGE:
- rec = "ZERO_OFF_PAGE";
- break;
- case XLOG_MULTIXACT_ZERO_MEM_PAGE:
- rec = "ZERO_MEM_PAGE";
- break;
- case XLOG_MULTIXACT_CREATE_ID:
- rec = "CREATE_ID";
- break;
- }
- break;
-
- case RM_RELMAP_ID:
- switch (info)
- {
- case XLOG_RELMAP_UPDATE:
- rec = "UPDATE";
- break;
- }
- break;
-
- case RM_STANDBY_ID:
- switch (info)
- {
- case XLOG_STANDBY_LOCK:
- rec = "LOCK";
- break;
- case XLOG_RUNNING_XACTS:
- rec = "RUNNING_XACTS";
- break;
- }
- break;
-
- case RM_HEAP2_ID:
- switch (info & XLOG_HEAP_OPMASK)
- {
- case XLOG_HEAP2_CLEAN:
- rec = "CLEAN";
- break;
- case XLOG_HEAP2_FREEZE_PAGE:
- rec = "FREEZE_PAGE";
- break;
- case XLOG_HEAP2_CLEANUP_INFO:
- rec = "CLEANUP_INFO";
- break;
- case XLOG_HEAP2_VISIBLE:
- rec = "VISIBLE";
- break;
- case XLOG_HEAP2_MULTI_INSERT:
- rec = "MULTI_INSERT";
- break;
- case XLOG_HEAP2_LOCK_UPDATED:
- rec = "LOCK_UPDATED";
- break;
- case XLOG_HEAP2_NEW_CID:
- rec = "NEW_CID";
- break;
- case XLOG_HEAP2_REWRITE:
- rec = "REWRITE";
- break;
- }
-
- if (info & XLOG_HEAP_INIT_PAGE)
- rec = psprintf("%s+INIT", rec);
-
- break;
-
- case RM_HEAP_ID:
- switch (info & XLOG_HEAP_OPMASK)
- {
- case XLOG_HEAP_INSERT:
- rec = "INSERT";
- break;
- case XLOG_HEAP_DELETE:
- rec = "DELETE";
- break;
- case XLOG_HEAP_UPDATE:
- rec = "UPDATE";
- break;
- case XLOG_HEAP_HOT_UPDATE:
- rec = "HOT_UPDATE";
- break;
- case XLOG_HEAP_NEWPAGE:
- rec = "NEWPAGE";
- break;
- case XLOG_HEAP_LOCK:
- rec = "LOCK";
- break;
- case XLOG_HEAP_INPLACE:
- rec = "INPLACE";
- break;
- }
-
- if (info & XLOG_HEAP_INIT_PAGE)
- rec = psprintf("%s+INIT", rec);
-
- break;
-
- case RM_BTREE_ID:
- switch (info)
- {
- case XLOG_BTREE_INSERT_LEAF:
- rec = "INSERT_LEAF";
- break;
- case XLOG_BTREE_INSERT_UPPER:
- rec = "INSERT_UPPER";
- break;
- case XLOG_BTREE_INSERT_META:
- rec = "INSERT_META";
- break;
- case XLOG_BTREE_SPLIT_L:
- rec = "SPLIT_L";
- break;
- case XLOG_BTREE_SPLIT_R:
- rec = "SPLIT_R";
- break;
- case XLOG_BTREE_SPLIT_L_ROOT:
- rec = "SPLIT_L_ROOT";
- break;
- case XLOG_BTREE_SPLIT_R_ROOT:
- rec = "SPLIT_R_ROOT";
- break;
- case XLOG_BTREE_VACUUM:
- rec = "VACUUM";
- break;
- case XLOG_BTREE_DELETE:
- rec = "DELETE";
- break;
- case XLOG_BTREE_MARK_PAGE_HALFDEAD:
- rec = "MARK_PAGE_HALFDEAD";
- break;
- case XLOG_BTREE_UNLINK_PAGE:
- rec = "UNLINK_PAGE";
- break;
- case XLOG_BTREE_UNLINK_PAGE_META:
- rec = "UNLINK_PAGE_META";
- break;
- case XLOG_BTREE_NEWROOT:
- rec = "NEWROOT";
- break;
- case XLOG_BTREE_REUSE_PAGE:
- rec = "REUSE_PAGE";
- break;
- }
- break;
-
- case RM_HASH_ID:
- break;
-
- case RM_GIN_ID:
- switch (info)
- {
- case XLOG_GIN_CREATE_INDEX:
- rec = "CREATE_INDEX";
- break;
- case XLOG_GIN_CREATE_PTREE:
- rec = "CREATE_PTREE";
- break;
- case XLOG_GIN_INSERT:
- rec = "INSERT";
- break;
- case XLOG_GIN_SPLIT:
- rec = "SPLIT";
- break;
- case XLOG_GIN_VACUUM_PAGE:
- rec = "VACUUM_PAGE";
- break;
- case XLOG_GIN_VACUUM_DATA_LEAF_PAGE:
- rec = "VACUUM_DATA_LEAF_PAGE";
- break;
- case XLOG_GIN_DELETE_PAGE:
- rec = "DELETE_PAGE";
- break;
- case XLOG_GIN_UPDATE_META_PAGE:
- rec = "UPDATE_META_PAGE";
- break;
- case XLOG_GIN_INSERT_LISTPAGE:
- rec = "INSERT_LISTPAGE";
- break;
- case XLOG_GIN_DELETE_LISTPAGE:
- rec = "DELETE_LISTPAGE";
- break;
- }
- break;
-
- case RM_GIST_ID:
- switch (info)
- {
- case XLOG_GIST_PAGE_UPDATE:
- rec = "PAGE_UPDATE";
- break;
- case XLOG_GIST_PAGE_SPLIT:
- rec = "PAGE_SPLIT";
- break;
- case XLOG_GIST_CREATE_INDEX:
- rec = "CREATE_INDEX";
- break;
- }
- break;
-
- case RM_SEQ_ID:
- switch (info)
- {
- case XLOG_SEQ_LOG:
- rec = "LOG";
- break;
- }
- break;
-
- case RM_SPGIST_ID:
- switch (info)
- {
- case XLOG_SPGIST_CREATE_INDEX:
- rec = "CREATE_INDEX";
- break;
- case XLOG_SPGIST_ADD_LEAF:
- rec = "ADD_LEAF";
- break;
- case XLOG_SPGIST_MOVE_LEAFS:
- rec = "MOVE_LEAFS";
- break;
- case XLOG_SPGIST_ADD_NODE:
- rec = "ADD_NODE";
- break;
- case XLOG_SPGIST_SPLIT_TUPLE:
- rec = "SPLIT_TUPLE";
- break;
- case XLOG_SPGIST_PICKSPLIT:
- rec = "PICKSPLIT";
- break;
- case XLOG_SPGIST_VACUUM_LEAF:
- rec = "VACUUM_LEAF";
- break;
- case XLOG_SPGIST_VACUUM_ROOT:
- rec = "VACUUM_ROOT";
- break;
- case XLOG_SPGIST_VACUUM_REDIRECT:
- rec = "VACUUM_REDIRECT";
- break;
- }
- break;
-
- default:
- break;
- }
-
- return psprintf("%s/%s", desc->rm_name, rec);
-}
-
-/*
* Display a single row of record counts and sizes for an rmgr or record.
*/
static void
@@ -894,11 +499,10 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats)
for (ri = 0; ri < RM_NEXT_ID; ri++)
{
uint64 count, rec_len, fpi_len;
+ const RmgrDescData *desc = &RmgrDescTable[ri];
if (!config->stats_per_record)
{
- const RmgrDescData *desc = &RmgrDescTable[ri];
-
count = stats->rmgr_stats[ri].count;
rec_len = stats->rmgr_stats[ri].rec_len;
fpi_len = stats->rmgr_stats[ri].fpi_len;
@@ -913,6 +517,8 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats)
{
for (rj = 0; rj < 16; rj++)
{
+ const char *id;
+
count = stats->record_stats[ri][rj].count;
rec_len = stats->record_stats[ri][rj].rec_len;
fpi_len = stats->record_stats[ri][rj].fpi_len;
@@ -921,7 +527,11 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats)
if (count == 0)
continue;
- XLogDumpStatsRow(identify_record(ri, rj << 4),
+ id = desc->rm_identify(rj << 4);
+ if (id == NULL)
+ id = psprintf("0x%x", rj << 4);
+
+ XLogDumpStatsRow(psprintf("%s/%s", desc->rm_name, id),
count, 100*(double)count/total_count,
rec_len, 100*(double)rec_len/total_rec_len,
fpi_len, 100*(double)fpi_len/total_fpi_len,
diff --git a/contrib/pg_xlogdump/rmgrdesc.c b/contrib/pg_xlogdump/rmgrdesc.c
index cbcaaa6..dc27fd1 100644
--- a/contrib/pg_xlogdump/rmgrdesc.c
+++ b/contrib/pg_xlogdump/rmgrdesc.c
@@ -27,8 +27,8 @@
#include "storage/standby.h"
#include "utils/relmapper.h"
-#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \
- { name, desc, },
+#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \
+ { name, desc, identify, },
const RmgrDescData RmgrDescTable[RM_MAX_ID + 1] = {
#include "access/rmgrlist.h"
diff --git a/contrib/pg_xlogdump/rmgrdesc.h b/contrib/pg_xlogdump/rmgrdesc.h
index d964118..da805c5 100644
--- a/contrib/pg_xlogdump/rmgrdesc.h
+++ b/contrib/pg_xlogdump/rmgrdesc.h
@@ -14,6 +14,7 @@ typedef struct RmgrDescData
{
const char *rm_name;
void (*rm_desc) (StringInfo buf, XLogRecord *record);
+ const char *(*rm_identify) (uint8 info);
} RmgrDescData;
extern const RmgrDescData RmgrDescTable[];
diff --git a/src/backend/access/rmgrdesc/clogdesc.c b/src/backend/access/rmgrdesc/clogdesc.c
index e82baa8..08f225d 100644
--- a/src/backend/access/rmgrdesc/clogdesc.c
+++ b/src/backend/access/rmgrdesc/clogdesc.c
@@ -40,3 +40,21 @@ clog_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+clog_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case CLOG_ZEROPAGE:
+ id = "ZEROPAGE";
+ break;
+ case CLOG_TRUNCATE:
+ id = "TRUNCATE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/dbasedesc.c b/src/backend/access/rmgrdesc/dbasedesc.c
index 0230716..38f3a39 100644
--- a/src/backend/access/rmgrdesc/dbasedesc.c
+++ b/src/backend/access/rmgrdesc/dbasedesc.c
@@ -42,3 +42,21 @@ dbase_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+dbase_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_DBASE_CREATE:
+ id = "CREATE";
+ break;
+ case XLOG_DBASE_DROP:
+ id = "DROP";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/gindesc.c b/src/backend/access/rmgrdesc/gindesc.c
index 12d68d7..115ad5b 100644
--- a/src/backend/access/rmgrdesc/gindesc.c
+++ b/src/backend/access/rmgrdesc/gindesc.c
@@ -187,3 +187,45 @@ gin_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+gin_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_GIN_CREATE_INDEX:
+ id = "CREATE_INDEX";
+ break;
+ case XLOG_GIN_CREATE_PTREE:
+ id = "CREATE_PTREE";
+ break;
+ case XLOG_GIN_INSERT:
+ id = "INSERT";
+ break;
+ case XLOG_GIN_SPLIT:
+ id = "SPLIT";
+ break;
+ case XLOG_GIN_VACUUM_PAGE:
+ id = "VACUUM_PAGE";
+ break;
+ case XLOG_GIN_VACUUM_DATA_LEAF_PAGE:
+ id = "VACUUM_DATA_LEAF_PAGE";
+ break;
+ case XLOG_GIN_DELETE_PAGE:
+ id = "DELETE_PAGE";
+ break;
+ case XLOG_GIN_UPDATE_META_PAGE:
+ id = "UPDATE_META_PAGE";
+ break;
+ case XLOG_GIN_INSERT_LISTPAGE:
+ id = "INSERT_LISTPAGE";
+ break;
+ case XLOG_GIN_DELETE_LISTPAGE:
+ id = "DELETE_LISTPAGE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/gistdesc.c b/src/backend/access/rmgrdesc/gistdesc.c
index cdac496..e4f288b 100644
--- a/src/backend/access/rmgrdesc/gistdesc.c
+++ b/src/backend/access/rmgrdesc/gistdesc.c
@@ -67,3 +67,24 @@ gist_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+gist_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_GIST_PAGE_UPDATE:
+ id = "PAGE_UPDATE";
+ break;
+ case XLOG_GIST_PAGE_SPLIT:
+ id = "PAGE_SPLIT";
+ break;
+ case XLOG_GIST_CREATE_INDEX:
+ id = "CREATE_INDEX";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/hashdesc.c b/src/backend/access/rmgrdesc/hashdesc.c
index 86a0376..c58461c 100644
--- a/src/backend/access/rmgrdesc/hashdesc.c
+++ b/src/backend/access/rmgrdesc/hashdesc.c
@@ -20,3 +20,9 @@ void
hash_desc(StringInfo buf, XLogRecord *record)
{
}
+
+const char *
+hash_identify(uint8 info)
+{
+ return NULL;
+}
diff --git a/src/backend/access/rmgrdesc/heapdesc.c b/src/backend/access/rmgrdesc/heapdesc.c
index 7df18fa..e6149be 100644
--- a/src/backend/access/rmgrdesc/heapdesc.c
+++ b/src/backend/access/rmgrdesc/heapdesc.c
@@ -202,3 +202,78 @@ heap2_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+heap_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info & XLOG_HEAP_OPMASK)
+ {
+ case XLOG_HEAP_INSERT:
+ id = "INSERT";
+ break;
+ case XLOG_HEAP_DELETE:
+ id = "DELETE";
+ break;
+ case XLOG_HEAP_UPDATE:
+ id = "UPDATE";
+ break;
+ case XLOG_HEAP_HOT_UPDATE:
+ id = "HOT_UPDATE";
+ break;
+ case XLOG_HEAP_NEWPAGE:
+ id = "NEWPAGE";
+ break;
+ case XLOG_HEAP_LOCK:
+ id = "LOCK";
+ break;
+ case XLOG_HEAP_INPLACE:
+ id = "INPLACE";
+ break;
+ }
+
+ if (info & XLOG_HEAP_INIT_PAGE)
+ id = psprintf("%s+INIT", id);
+
+ return id;
+}
+
+const char *
+heap2_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info & XLOG_HEAP_OPMASK)
+ {
+ case XLOG_HEAP2_CLEAN:
+ id = "CLEAN";
+ break;
+ case XLOG_HEAP2_FREEZE_PAGE:
+ id = "FREEZE_PAGE";
+ break;
+ case XLOG_HEAP2_CLEANUP_INFO:
+ id = "CLEANUP_INFO";
+ break;
+ case XLOG_HEAP2_VISIBLE:
+ id = "VISIBLE";
+ break;
+ case XLOG_HEAP2_MULTI_INSERT:
+ id = "MULTI_INSERT";
+ break;
+ case XLOG_HEAP2_LOCK_UPDATED:
+ id = "LOCK_UPDATED";
+ break;
+ case XLOG_HEAP2_NEW_CID:
+ id = "NEW_CID";
+ break;
+ case XLOG_HEAP2_REWRITE:
+ id = "REWRITE";
+ break;
+ }
+
+ if (info & XLOG_HEAP_INIT_PAGE)
+ id = psprintf("%s+INIT", id);
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/mxactdesc.c b/src/backend/access/rmgrdesc/mxactdesc.c
index 50d9b55..d77b1c8 100644
--- a/src/backend/access/rmgrdesc/mxactdesc.c
+++ b/src/backend/access/rmgrdesc/mxactdesc.c
@@ -79,3 +79,24 @@ multixact_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+multixact_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_MULTIXACT_ZERO_OFF_PAGE:
+ id = "ZERO_OFF_PAGE";
+ break;
+ case XLOG_MULTIXACT_ZERO_MEM_PAGE:
+ id = "ZERO_MEM_PAGE";
+ break;
+ case XLOG_MULTIXACT_CREATE_ID:
+ id = "CREATE_ID";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/nbtdesc.c b/src/backend/access/rmgrdesc/nbtdesc.c
index bf3389c..821715c 100644
--- a/src/backend/access/rmgrdesc/nbtdesc.c
+++ b/src/backend/access/rmgrdesc/nbtdesc.c
@@ -172,3 +172,57 @@ btree_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+btree_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_BTREE_INSERT_LEAF:
+ id = "INSERT_LEAF";
+ break;
+ case XLOG_BTREE_INSERT_UPPER:
+ id = "INSERT_UPPER";
+ break;
+ case XLOG_BTREE_INSERT_META:
+ id = "INSERT_META";
+ break;
+ case XLOG_BTREE_SPLIT_L:
+ id = "SPLIT_L";
+ break;
+ case XLOG_BTREE_SPLIT_R:
+ id = "SPLIT_R";
+ break;
+ case XLOG_BTREE_SPLIT_L_ROOT:
+ id = "SPLIT_L_ROOT";
+ break;
+ case XLOG_BTREE_SPLIT_R_ROOT:
+ id = "SPLIT_R_ROOT";
+ break;
+ case XLOG_BTREE_VACUUM:
+ id = "VACUUM";
+ break;
+ case XLOG_BTREE_DELETE:
+ id = "DELETE";
+ break;
+ case XLOG_BTREE_MARK_PAGE_HALFDEAD:
+ id = "MARK_PAGE_HALFDEAD";
+ break;
+ case XLOG_BTREE_UNLINK_PAGE:
+ id = "UNLINK_PAGE";
+ break;
+ case XLOG_BTREE_UNLINK_PAGE_META:
+ id = "UNLINK_PAGE_META";
+ break;
+ case XLOG_BTREE_NEWROOT:
+ id = "NEWROOT";
+ break;
+ case XLOG_BTREE_REUSE_PAGE:
+ id = "REUSE_PAGE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/relmapdesc.c b/src/backend/access/rmgrdesc/relmapdesc.c
index 06fd4b3..2aebf22 100644
--- a/src/backend/access/rmgrdesc/relmapdesc.c
+++ b/src/backend/access/rmgrdesc/relmapdesc.c
@@ -32,3 +32,18 @@ relmap_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+relmap_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_RELMAP_UPDATE:
+ id = "UPDATE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/seqdesc.c b/src/backend/access/rmgrdesc/seqdesc.c
index 42eb9b9..157c7c6 100644
--- a/src/backend/access/rmgrdesc/seqdesc.c
+++ b/src/backend/access/rmgrdesc/seqdesc.c
@@ -35,3 +35,18 @@ seq_desc(StringInfo buf, XLogRecord *record)
appendStringInfo(buf, "rel %u/%u/%u",
xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
}
+
+const char *
+seq_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_SEQ_LOG:
+ id = "LOG";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/smgrdesc.c b/src/backend/access/rmgrdesc/smgrdesc.c
index c76c815..0a7a6e2 100644
--- a/src/backend/access/rmgrdesc/smgrdesc.c
+++ b/src/backend/access/rmgrdesc/smgrdesc.c
@@ -44,3 +44,21 @@ smgr_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+smgr_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_SMGR_CREATE:
+ id = "CREATE";
+ break;
+ case XLOG_SMGR_TRUNCATE:
+ id = "TRUNCATE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/spgdesc.c b/src/backend/access/rmgrdesc/spgdesc.c
index ed369b2..76f43ff 100644
--- a/src/backend/access/rmgrdesc/spgdesc.c
+++ b/src/backend/access/rmgrdesc/spgdesc.c
@@ -88,3 +88,42 @@ spg_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+spg_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_SPGIST_CREATE_INDEX:
+ id = "CREATE_INDEX";
+ break;
+ case XLOG_SPGIST_ADD_LEAF:
+ id = "ADD_LEAF";
+ break;
+ case XLOG_SPGIST_MOVE_LEAFS:
+ id = "MOVE_LEAFS";
+ break;
+ case XLOG_SPGIST_ADD_NODE:
+ id = "ADD_NODE";
+ break;
+ case XLOG_SPGIST_SPLIT_TUPLE:
+ id = "SPLIT_TUPLE";
+ break;
+ case XLOG_SPGIST_PICKSPLIT:
+ id = "PICKSPLIT";
+ break;
+ case XLOG_SPGIST_VACUUM_LEAF:
+ id = "VACUUM_LEAF";
+ break;
+ case XLOG_SPGIST_VACUUM_ROOT:
+ id = "VACUUM_ROOT";
+ break;
+ case XLOG_SPGIST_VACUUM_REDIRECT:
+ id = "VACUUM_REDIRECT";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/standbydesc.c b/src/backend/access/rmgrdesc/standbydesc.c
index a127d38..77503d4 100644
--- a/src/backend/access/rmgrdesc/standbydesc.c
+++ b/src/backend/access/rmgrdesc/standbydesc.c
@@ -64,3 +64,21 @@ standby_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+standby_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_STANDBY_LOCK:
+ id = "LOCK";
+ break;
+ case XLOG_RUNNING_XACTS:
+ id = "RUNNING_XACTS";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/tblspcdesc.c b/src/backend/access/rmgrdesc/tblspcdesc.c
index 30b1f06..c947845 100644
--- a/src/backend/access/rmgrdesc/tblspcdesc.c
+++ b/src/backend/access/rmgrdesc/tblspcdesc.c
@@ -39,3 +39,21 @@ tblspc_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+tblspc_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_TBLSPC_CREATE:
+ id = "CREATE";
+ break;
+ case XLOG_TBLSPC_DROP:
+ id = "DROP";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/xactdesc.c b/src/backend/access/rmgrdesc/xactdesc.c
index 994931e..8ea10c9 100644
--- a/src/backend/access/rmgrdesc/xactdesc.c
+++ b/src/backend/access/rmgrdesc/xactdesc.c
@@ -196,3 +196,36 @@ xact_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+xact_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_XACT_COMMIT:
+ id = "COMMIT";
+ break;
+ case XLOG_XACT_PREPARE:
+ id = "PREPARE";
+ break;
+ case XLOG_XACT_ABORT:
+ id = "ABORT";
+ break;
+ case XLOG_XACT_COMMIT_PREPARED:
+ id = "COMMIT_PREPARED";
+ break;
+ case XLOG_XACT_ABORT_PREPARED:
+ id = "ABORT_PREPARED";
+ break;
+ case XLOG_XACT_ASSIGNMENT:
+ id = "ASSIGNMENT";
+ break;
+ case XLOG_XACT_COMMIT_COMPACT:
+ id = "COMMIT_COMPACT";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/xlogdesc.c b/src/backend/access/rmgrdesc/xlogdesc.c
index 2224da1..04a1f24 100644
--- a/src/backend/access/rmgrdesc/xlogdesc.c
+++ b/src/backend/access/rmgrdesc/xlogdesc.c
@@ -144,3 +144,48 @@ xlog_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+xlog_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_CHECKPOINT_SHUTDOWN:
+ id = "CHECKPOINT_SHUTDOWN";
+ break;
+ case XLOG_CHECKPOINT_ONLINE:
+ id = "CHECKPOINT_ONLINE";
+ break;
+ case XLOG_NOOP:
+ id = "NOOP";
+ break;
+ case XLOG_NEXTOID:
+ id = "NEXTOID";
+ break;
+ case XLOG_SWITCH:
+ id = "SWITCH";
+ break;
+ case XLOG_BACKUP_END:
+ id = "BACKUP_END";
+ break;
+ case XLOG_PARAMETER_CHANGE:
+ id = "PARAMETER_CHANGE";
+ break;
+ case XLOG_RESTORE_POINT:
+ id = "RESTORE_POINT";
+ break;
+ case XLOG_FPW_CHANGE:
+ id = "FPW_CHANGE";
+ break;
+ case XLOG_END_OF_RECOVERY:
+ id = "END_OF_RECOVERY";
+ break;
+ case XLOG_FPI:
+ id = "FPI";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/transam/rmgr.c b/src/backend/access/transam/rmgr.c
index c0a7a6f..2645a7a 100644
--- a/src/backend/access/transam/rmgr.c
+++ b/src/backend/access/transam/rmgr.c
@@ -25,8 +25,8 @@
#include "utils/relmapper.h"
/* must be kept in sync with RmgrData definition in xlog_internal.h */
-#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \
- { name, redo, desc, startup, cleanup },
+#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \
+ { name, redo, desc, identify, startup, cleanup },
const RmgrData RmgrTable[RM_MAX_ID + 1] = {
#include "access/rmgrlist.h"
diff --git a/src/include/access/clog.h b/src/include/access/clog.h
index be9b867..8562631 100644
--- a/src/include/access/clog.h
+++ b/src/include/access/clog.h
@@ -49,5 +49,6 @@ extern void TruncateCLOG(TransactionId oldestXact);
extern void clog_redo(XLogRecPtr lsn, XLogRecord *record);
extern void clog_desc(StringInfo buf, XLogRecord *record);
+extern const char *clog_identify(uint8 info);
#endif /* CLOG_H */
diff --git a/src/include/access/gin.h b/src/include/access/gin.h
index a0b288d..0ebecb4 100644
--- a/src/include/access/gin.h
+++ b/src/include/access/gin.h
@@ -74,6 +74,7 @@ extern void ginUpdateStats(Relation index, const GinStatsData *stats);
/* ginxlog.c */
extern void gin_redo(XLogRecPtr lsn, XLogRecord *record);
extern void gin_desc(StringInfo buf, XLogRecord *record);
+extern const char *gin_identify(uint8 info);
extern void gin_xlog_startup(void);
extern void gin_xlog_cleanup(void);
diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h
index 03e9903..879f113 100644
--- a/src/include/access/gist_private.h
+++ b/src/include/access/gist_private.h
@@ -452,6 +452,7 @@ extern SplitedPageLayout *gistSplit(Relation r, Page page, IndexTuple *itup,
/* gistxlog.c */
extern void gist_redo(XLogRecPtr lsn, XLogRecord *record);
extern void gist_desc(StringInfo buf, XLogRecord *record);
+extern const char *gist_identify(uint8 info);
extern void gist_xlog_startup(void);
extern void gist_xlog_cleanup(void);
diff --git a/src/include/access/hash.h b/src/include/access/hash.h
index 2062801..0a7a82f 100644
--- a/src/include/access/hash.h
+++ b/src/include/access/hash.h
@@ -356,5 +356,6 @@ extern OffsetNumber _hash_binsearch_last(Page page, uint32 hash_value);
/* hash.c */
extern void hash_redo(XLogRecPtr lsn, XLogRecord *record);
extern void hash_desc(StringInfo buf, XLogRecord *record);
+extern const char *hash_identify(uint8 info);
#endif /* HASH_H */
diff --git a/src/include/access/heapam_xlog.h b/src/include/access/heapam_xlog.h
index 05beb00..0e00a11 100644
--- a/src/include/access/heapam_xlog.h
+++ b/src/include/access/heapam_xlog.h
@@ -369,8 +369,10 @@ extern void HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple,
extern void heap_redo(XLogRecPtr lsn, XLogRecord *record);
extern void heap_desc(StringInfo buf, XLogRecord *record);
+extern const char *heap_identify(uint8 info);
extern void heap2_redo(XLogRecPtr lsn, XLogRecord *record);
extern void heap2_desc(StringInfo buf, XLogRecord *record);
+extern const char *heap2_identify(uint8 info);
extern void heap_xlog_logical_rewrite(XLogRecPtr lsn, XLogRecord *r);
extern XLogRecPtr log_heap_cleanup_info(RelFileNode rnode,
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index f6d2e04..1910e7a 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -136,6 +136,7 @@ extern void multixact_twophase_postabort(TransactionId xid, uint16 info,
extern void multixact_redo(XLogRecPtr lsn, XLogRecord *record);
extern void multixact_desc(StringInfo buf, XLogRecord *record);
+extern const char *multixact_identify(uint8 info);
extern char *mxid_to_string(MultiXactId multi, int nmembers,
MultiXactMember *members);
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
index ed6f697..622383d 100644
--- a/src/include/access/nbtree.h
+++ b/src/include/access/nbtree.h
@@ -725,5 +725,6 @@ extern void _bt_leafbuild(BTSpool *btspool, BTSpool *spool2);
*/
extern void btree_redo(XLogRecPtr lsn, XLogRecord *record);
extern void btree_desc(StringInfo buf, XLogRecord *record);
+extern const char *btree_identify(uint8 info);
#endif /* NBTREE_H */
diff --git a/src/include/access/rmgr.h b/src/include/access/rmgr.h
index 1b577a2..ff7fe62 100644
--- a/src/include/access/rmgr.h
+++ b/src/include/access/rmgr.h
@@ -19,7 +19,7 @@ typedef uint8 RmgrId;
* Note: RM_MAX_ID must fit in RmgrId; widening that type will affect the XLOG
* file format.
*/
-#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \
+#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \
symname,
typedef enum RmgrIds
diff --git a/src/include/access/rmgrlist.h b/src/include/access/rmgrlist.h
index 662fb77..77d4574 100644
--- a/src/include/access/rmgrlist.h
+++ b/src/include/access/rmgrlist.h
@@ -25,20 +25,20 @@
*/
/* symbol name, textual name, redo, desc, startup, cleanup */
-PG_RMGR(RM_XLOG_ID, "XLOG", xlog_redo, xlog_desc, NULL, NULL)
-PG_RMGR(RM_XACT_ID, "Transaction", xact_redo, xact_desc, NULL, NULL)
-PG_RMGR(RM_SMGR_ID, "Storage", smgr_redo, smgr_desc, NULL, NULL)
-PG_RMGR(RM_CLOG_ID, "CLOG", clog_redo, clog_desc, NULL, NULL)
-PG_RMGR(RM_DBASE_ID, "Database", dbase_redo, dbase_desc, NULL, NULL)
-PG_RMGR(RM_TBLSPC_ID, "Tablespace", tblspc_redo, tblspc_desc, NULL, NULL)
-PG_RMGR(RM_MULTIXACT_ID, "MultiXact", multixact_redo, multixact_desc, NULL, NULL)
-PG_RMGR(RM_RELMAP_ID, "RelMap", relmap_redo, relmap_desc, NULL, NULL)
-PG_RMGR(RM_STANDBY_ID, "Standby", standby_redo, standby_desc, NULL, NULL)
-PG_RMGR(RM_HEAP2_ID, "Heap2", heap2_redo, heap2_desc, NULL, NULL)
-PG_RMGR(RM_HEAP_ID, "Heap", heap_redo, heap_desc, NULL, NULL)
-PG_RMGR(RM_BTREE_ID, "Btree", btree_redo, btree_desc, NULL, NULL)
-PG_RMGR(RM_HASH_ID, "Hash", hash_redo, hash_desc, NULL, NULL)
-PG_RMGR(RM_GIN_ID, "Gin", gin_redo, gin_desc, gin_xlog_startup, gin_xlog_cleanup)
-PG_RMGR(RM_GIST_ID, "Gist", gist_redo, gist_desc, gist_xlog_startup, gist_xlog_cleanup)
-PG_RMGR(RM_SEQ_ID, "Sequence", seq_redo, seq_desc, NULL, NULL)
-PG_RMGR(RM_SPGIST_ID, "SPGist", spg_redo, spg_desc, spg_xlog_startup, spg_xlog_cleanup)
+PG_RMGR(RM_XLOG_ID, "XLOG", xlog_redo, xlog_desc, xlog_identify, NULL, NULL)
+PG_RMGR(RM_XACT_ID, "Transaction", xact_redo, xact_desc, xact_identify, NULL, NULL)
+PG_RMGR(RM_SMGR_ID, "Storage", smgr_redo, smgr_desc, smgr_identify, NULL, NULL)
+PG_RMGR(RM_CLOG_ID, "CLOG", clog_redo, clog_desc, clog_identify, NULL, NULL)
+PG_RMGR(RM_DBASE_ID, "Database", dbase_redo, dbase_desc, dbase_identify, NULL, NULL)
+PG_RMGR(RM_TBLSPC_ID, "Tablespace", tblspc_redo, tblspc_desc, tblspc_identify, NULL, NULL)
+PG_RMGR(RM_MULTIXACT_ID, "MultiXact", multixact_redo, multixact_desc, multixact_identify, NULL, NULL)
+PG_RMGR(RM_RELMAP_ID, "RelMap", relmap_redo, relmap_desc, relmap_identify, NULL, NULL)
+PG_RMGR(RM_STANDBY_ID, "Standby", standby_redo, standby_desc, standby_identify, NULL, NULL)
+PG_RMGR(RM_HEAP2_ID, "Heap2", heap2_redo, heap2_desc, heap2_identify, NULL, NULL)
+PG_RMGR(RM_HEAP_ID, "Heap", heap_redo, heap_desc, heap_identify, NULL, NULL)
+PG_RMGR(RM_BTREE_ID, "Btree", btree_redo, btree_desc, btree_identify, NULL, NULL)
+PG_RMGR(RM_HASH_ID, "Hash", hash_redo, hash_desc, hash_identify, NULL, NULL)
+PG_RMGR(RM_GIN_ID, "Gin", gin_redo, gin_desc, gin_identify, gin_xlog_startup, gin_xlog_cleanup)
+PG_RMGR(RM_GIST_ID, "Gist", gist_redo, gist_desc, gist_identify, gist_xlog_startup, gist_xlog_cleanup)
+PG_RMGR(RM_SEQ_ID, "Sequence", seq_redo, seq_desc, seq_identify, NULL, NULL)
+PG_RMGR(RM_SPGIST_ID, "SPGist", spg_redo, spg_desc, spg_identify, spg_xlog_startup, spg_xlog_cleanup)
diff --git a/src/include/access/spgist.h b/src/include/access/spgist.h
index 7f8655c..f218a83 100644
--- a/src/include/access/spgist.h
+++ b/src/include/access/spgist.h
@@ -198,6 +198,7 @@ extern Datum spgvacuumcleanup(PG_FUNCTION_ARGS);
/* spgxlog.c */
extern void spg_redo(XLogRecPtr lsn, XLogRecord *record);
extern void spg_desc(StringInfo buf, XLogRecord *record);
+extern const char *spg_identify(uint8 info);
extern void spg_xlog_startup(void);
extern void spg_xlog_cleanup(void);
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 10ee943..ff7c426 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -257,5 +257,6 @@ extern int xactGetCommittedChildren(TransactionId **ptr);
extern void xact_redo(XLogRecPtr lsn, XLogRecord *record);
extern void xact_desc(StringInfo buf, XLogRecord *record);
+extern const char *xact_identify(uint8 info);
#endif /* XACT_H */
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 85f9cb7..e16d43c 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -299,6 +299,7 @@ extern Buffer RestoreBackupBlock(XLogRecPtr lsn, XLogRecord *record,
extern void xlog_redo(XLogRecPtr lsn, XLogRecord *record);
extern void xlog_desc(StringInfo buf, XLogRecord *record);
+extern const char *xlog_identify(uint8 info);
extern void issue_xlog_fsync(int fd, XLogSegNo segno);
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index 8c8de38..5839426 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -246,6 +246,7 @@ typedef struct RmgrData
const char *rm_name;
void (*rm_redo) (XLogRecPtr lsn, struct XLogRecord *rptr);
void (*rm_desc) (StringInfo buf, struct XLogRecord *rptr);
+ const char *(*rm_identify) (uint8 info);
void (*rm_startup) (void);
void (*rm_cleanup) (void);
} RmgrData;
diff --git a/src/include/catalog/storage_xlog.h b/src/include/catalog/storage_xlog.h
index 7081c99..5fc7235 100644
--- a/src/include/catalog/storage_xlog.h
+++ b/src/include/catalog/storage_xlog.h
@@ -45,5 +45,6 @@ extern void log_smgrcreate(RelFileNode *rnode, ForkNumber forkNum);
extern void smgr_redo(XLogRecPtr lsn, XLogRecord *record);
extern void smgr_desc(StringInfo buf, XLogRecord *record);
+extern const char *smgr_identify(uint8 info);
#endif /* STORAGE_XLOG_H */
diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h
index c2380dc..811713f 100644
--- a/src/include/commands/dbcommands.h
+++ b/src/include/commands/dbcommands.h
@@ -64,6 +64,7 @@ extern char *get_database_name(Oid dbid);
extern void dbase_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void dbase_desc(StringInfo buf, XLogRecord *rptr);
+extern const char *dbase_identify(uint8 info);
extern void check_encoding_locale_matches(int encoding, const char *collate, const char *ctype);
diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h
index 8819c00..914d155 100644
--- a/src/include/commands/sequence.h
+++ b/src/include/commands/sequence.h
@@ -78,5 +78,6 @@ extern void ResetSequenceCaches(void);
extern void seq_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void seq_desc(StringInfo buf, XLogRecord *rptr);
+extern const char *seq_identify(uint8 info);
#endif /* SEQUENCE_H */
diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h
index 073cb0d..5823bd9 100644
--- a/src/include/commands/tablespace.h
+++ b/src/include/commands/tablespace.h
@@ -58,5 +58,6 @@ extern bool directory_is_empty(const char *path);
extern void tblspc_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void tblspc_desc(StringInfo buf, XLogRecord *rptr);
+extern const char *tblspc_identify(uint8 info);
#endif /* TABLESPACE_H */
diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h
index da22fd3..1c63af5 100644
--- a/src/include/storage/standby.h
+++ b/src/include/storage/standby.h
@@ -83,6 +83,7 @@ typedef struct xl_running_xacts
/* Recovery handlers for the Standby Rmgr (RM_STANDBY_ID) */
extern void standby_redo(XLogRecPtr lsn, XLogRecord *record);
extern void standby_desc(StringInfo buf, XLogRecord *record);
+extern const char *standby_identify(uint8 info);
/*
* Declarations for GetRunningTransactionData(). Similar to Snapshots, but
diff --git a/src/include/utils/relmapper.h b/src/include/utils/relmapper.h
index 76bcf18..37937dd 100644
--- a/src/include/utils/relmapper.h
+++ b/src/include/utils/relmapper.h
@@ -60,5 +60,6 @@ extern void RelationMapInitializePhase3(void);
extern void relmap_redo(XLogRecPtr lsn, XLogRecord *record);
extern void relmap_desc(StringInfo buf, XLogRecord *record);
+extern const char *relmap_identify(uint8 info);
#endif /* RELMAPPER_H */
At 2014-06-30 12:05:06 +0530, ams@2ndQuadrant.com wrote:
It may be that the best thing to do would be to avoid using
optional_argument altogether, and have separate --stats and
--stats-per-record options. Thoughts?
That's what I've done in the attached patch, except I've called the new
option --record-stats. Both options now use no_argument. This should
apply on top of the diff I posted a little while ago.
-- Abhijit
Attachments:
stats-newopt.difftext/x-diff; charset=us-asciiDownload
commit cc9422aa71ef0b507c634282272be3fd15c39c0b
Author: Abhijit Menon-Sen <ams@2ndQuadrant.com>
Date: Mon Jun 30 12:15:54 2014 +0530
Introduce --record-stats to avoid use of optional_argument
diff --git a/contrib/pg_xlogdump/pg_xlogdump.c b/contrib/pg_xlogdump/pg_xlogdump.c
index 47838d4..1853b47 100644
--- a/contrib/pg_xlogdump/pg_xlogdump.c
+++ b/contrib/pg_xlogdump/pg_xlogdump.c
@@ -609,7 +609,8 @@ main(int argc, char **argv)
{"timeline", required_argument, NULL, 't'},
{"xid", required_argument, NULL, 'x'},
{"version", no_argument, NULL, 'V'},
- {"stats", optional_argument, NULL, 'z'},
+ {"stats", no_argument, NULL, 'z'},
+ {"record-stats", no_argument, NULL, 'Z'},
{NULL, 0, NULL, 0}
};
@@ -643,7 +644,7 @@ main(int argc, char **argv)
goto bad_argument;
}
- while ((option = getopt_long(argc, argv, "be:?fn:p:r:s:t:Vx:z::",
+ while ((option = getopt_long(argc, argv, "be:?fn:p:r:s:t:Vx:zZ",
long_options, &optindex)) != -1)
{
switch (option)
@@ -738,18 +739,10 @@ main(int argc, char **argv)
break;
case 'z':
config.stats = true;
- config.stats_per_record = false;
- if (optarg)
- {
- if (strcmp(optarg, "record") == 0)
- config.stats_per_record = true;
- else if (strcmp(optarg, "rmgr") != 0)
- {
- fprintf(stderr, "%s: unrecognised argument to --stats: %s\n",
- progname, optarg);
- goto bad_argument;
- }
- }
+ break;
+ case 'Z':
+ config.stats = true;
+ config.stats_per_record = true;
break;
default:
goto bad_argument;
diff --git a/doc/src/sgml/pg_xlogdump.sgml b/doc/src/sgml/pg_xlogdump.sgml
index d9f4a6a..bfd9eb9 100644
--- a/doc/src/sgml/pg_xlogdump.sgml
+++ b/doc/src/sgml/pg_xlogdump.sgml
@@ -181,12 +181,22 @@ PostgreSQL documentation
<varlistentry>
<term><option>-z</option></term>
- <term><option>--stats[=record]</option></term>
+ <term><option>--stats</option></term>
<listitem>
<para>
Display summary statistics (number and size of records and
- full-page images) instead of individual records. Optionally
- generate statistics per-record instead of per-rmgr.
+ full-page images per rmgr) instead of individual records.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-Z</option></term>
+ <term><option>--record-stats</option></term>
+ <listitem>
+ <para>
+ Display summary statistics (number and size of records and
+ full-page images) instead of individual records.
</para>
</listitem>
</varlistentry>
On Wed, Jun 4, 2014 at 1:47 PM, Abhijit Menon-Sen <ams@2ndquadrant.com> wrote:
Here's a patch to make pg_xlogdump print summary statistics instead of
individual records.
Thanks! I had a use for this feature so I backported the (first) patch
to PostgreSQL 9.3. It's a rush job so it's ugly and may have bugs, but
it works for me. Just posting here, maybe someone else will find it
useful too.
Regards,
Marti
Attachments:
At 2014-07-01 16:39:57 +0300, marti@juffo.org wrote:
Here's a patch to make pg_xlogdump print summary statistics instead
of individual records.Thanks! I had a use for this feature so I backported the (first) patch
to PostgreSQL 9.3. It's a rush job so it's ugly and may have bugs, but
it works for me. Just posting here, maybe someone else will find it
useful too.
Thanks for taking the trouble.
In CF terms, did you form any opinion while porting the patch I posted
about whether it's sensible/ready for inclusion in 9.5?
-- Abhijit
P.S. In your patch, the documentation changes are duplicated.
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Tue, Jul 1, 2014 at 11:13 PM, Abhijit Menon-Sen <ams@2ndquadrant.com> wrote:
In CF terms, did you form any opinion while porting the patch I posted
about whether it's sensible/ready for inclusion in 9.5?
I didn't look at the code more than necessary to make the build work.
As far as functionality goes, it does exactly what I needed it to do;
the output is very clear. I wanted to see how much WAL is being
generated from SELECT FOR UPDATE locks.
Here are some thoughts:
The "FPI" acronym made me wonder at first. Perhaps "Full page image
size" would be clearer (exactly 20 characters long, so it fits).
But on the other hand, I find that the table is too wide, I always
need to stretch my terminal window to fit it. I don't think we need to
accommodate for 10^20 bytes ~ 87 exabytes of WAL files. :)
You might also add units (kB/MB) to the table like pg_size_pretty,
although that would make the magnitudes harder to gauge.
P.S. In your patch, the documentation changes are duplicated.
Oh right you are, I don't know how that happened. I also missed some
record types (Btree/0x80, Btree/0xb0).
Regards,
Marti
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
At 2014-07-02 04:20:31 +0300, marti@juffo.org wrote:
As far as functionality goes, it does exactly what I needed it to do;
the output is very clear.
Good to hear.
You might also add units (kB/MB) to the table like pg_size_pretty,
although that would make the magnitudes harder to gauge.
I think df-style -k/m/g switches might be useful to scale all printed
values. If we did that, we could also shrink the columns accordingly.
But that would also complicate the code a bit. I think it's better to
start with the simplest thing, and add more tweaks later.
-- Abhijit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 07/02/2014 09:20 AM, Marti Raudsepp wrote:
You might also add units (kB/MB) to the table like pg_size_pretty,
although that would make the magnitudes harder to gauge.
What 'du' does, or a subset of, may be worthwhile.
-k: kB
-b: blocks
-m: MB
-h: human-readable auto-scaling
though I think just the "-h" flag would be useful here, meaning "wrap in
pg_size_pretty".
--
Craig Ringer http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
At 2014-06-30 05:19:10 +0000, dilip.kumar@huawei.com wrote:
Please fix these issues and send the updated patch..
I will continue reviewing the patch..
Did you get anywhere with the updated patch?
-- Abhijit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 04 July 2014 12:07, Abhijit Menon-Sen Wrote,
-----Original Message-----
From: Abhijit Menon-Sen [mailto:ams@2ndQuadrant.com]
Sent: 04 July 2014 12:07
To: Dilip kumar
Cc: pgsql-hackers@postgresql.org; furuyao@pm.nttdata.co.jp
Subject: Re: [HACKERS] pg_xlogdump --statsAt 2014-06-30 05:19:10 +0000, dilip.kumar@huawei.com wrote:
Please fix these issues and send the updated patch..
I will continue reviewing the patch..
Did you get anywhere with the updated patch?
Patch looks fine to me, except few small comments.
1. Update this new option in "usage" function also this still have the old way { -z, --stats[=record] }
{"stats", no_argument, NULL, 'z'},
{"record-stats", no_argument, NULL, 'Z'},
2. While applying stats-newopt.dif (after applying stat2.diff), some error in merging sgml file.
patching file `doc/src/sgml/pg_xlogdump.sgml'
Hunk #1 FAILED at 181.
1 out of 1 hunk FAILED -- saving rejects to doc/src/sgml/pg_xlogdump.sgml.rej
Once you fix above erros, I think patch is ok from my side.
Thanks & Regards,
Dilip Kumar
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
At 2014-07-04 08:38:17 +0000, dilip.kumar@huawei.com wrote:
Once you fix above erros, I think patch is ok from my side.
I've attached two updated patches here, including the fix to the usage
message. I'll mark this ready for committer now. (The rm_identify patch
is posted separately from the xlogdump one only to make the whole thing
easier to follow.)
Thank you.
-- Abhijit
Attachments:
xlogdump-stats.difftext/x-diff; charset=us-asciiDownload
diff --git a/contrib/pg_xlogdump/pg_xlogdump.c b/contrib/pg_xlogdump/pg_xlogdump.c
index c555786..239321f 100644
--- a/contrib/pg_xlogdump/pg_xlogdump.c
+++ b/contrib/pg_xlogdump/pg_xlogdump.c
@@ -15,12 +15,28 @@
#include <dirent.h>
#include <unistd.h>
+#include "access/clog.h"
+#include "access/gin_private.h"
+#include "access/gist_private.h"
+#include "access/heapam_xlog.h"
+#include "access/heapam_xlog.h"
+#include "access/multixact.h"
+#include "access/nbtree.h"
+#include "access/spgist_private.h"
+#include "access/xact.h"
#include "access/xlog.h"
#include "access/xlogreader.h"
#include "access/transam.h"
+#include "catalog/pg_control.h"
+#include "catalog/storage_xlog.h"
+#include "commands/dbcommands.h"
+#include "commands/sequence.h"
+#include "commands/tablespace.h"
#include "common/fe_memutils.h"
#include "getopt_long.h"
#include "rmgrdesc.h"
+#include "storage/standby.h"
+#include "utils/relmapper.h"
static const char *progname;
@@ -41,6 +57,8 @@ typedef struct XLogDumpConfig
int stop_after_records;
int already_displayed_records;
bool follow;
+ bool stats;
+ bool stats_per_record;
/* filter options */
int filter_by_rmgr;
@@ -48,6 +66,20 @@ typedef struct XLogDumpConfig
bool filter_by_xid_enabled;
} XLogDumpConfig;
+typedef struct Stats
+{
+ uint64 count;
+ uint64 rec_len;
+ uint64 fpi_len;
+} Stats;
+
+typedef struct XLogDumpStats
+{
+ uint64 count;
+ Stats rmgr_stats[RM_NEXT_ID];
+ Stats record_stats[RM_NEXT_ID][16];
+} XLogDumpStats;
+
static void
fatal_error(const char *fmt,...)
__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
@@ -322,6 +354,50 @@ XLogDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen,
}
/*
+ * Store per-rmgr and per-record statistics for a given record.
+ */
+static void
+XLogDumpCountRecord(XLogDumpConfig *config, XLogDumpStats *stats, XLogRecPtr ReadRecPtr, XLogRecord *record)
+{
+ RmgrId rmid;
+ uint8 recid;
+
+ if (config->filter_by_rmgr != -1 &&
+ config->filter_by_rmgr != record->xl_rmid)
+ return;
+
+ if (config->filter_by_xid_enabled &&
+ config->filter_by_xid != record->xl_xid)
+ return;
+
+ stats->count++;
+
+ /* Update per-rmgr statistics */
+
+ rmid = record->xl_rmid;
+
+ stats->rmgr_stats[rmid].count++;
+ stats->rmgr_stats[rmid].rec_len +=
+ record->xl_len + SizeOfXLogRecord;
+ stats->rmgr_stats[rmid].fpi_len +=
+ record->xl_tot_len - (record->xl_len + SizeOfXLogRecord);
+
+ /*
+ * Update per-record statistics, where the record is identified by a
+ * combination of the RmgrId and the upper four bits of the xl_info
+ * field (to give sixteen possible entries per RmgrId).
+ */
+
+ recid = (record->xl_info & ~XLR_INFO_MASK) >> 4;
+
+ stats->record_stats[rmid][recid].count++;
+ stats->record_stats[rmid][recid].rec_len +=
+ record->xl_len + SizeOfXLogRecord;
+ stats->record_stats[rmid][recid].fpi_len +=
+ record->xl_tot_len - (record->xl_len + SizeOfXLogRecord);
+}
+
+/*
* Print a record to stdout
*/
static void
@@ -380,6 +456,498 @@ XLogDumpDisplayRecord(XLogDumpConfig *config, XLogRecPtr ReadRecPtr, XLogRecord
}
}
+/*
+ * Given an xl_rmid and the high bits of xl_info, returns a string
+ * describing the record type.
+ */
+static const char *
+identify_record(RmgrId rmid, uint8 info)
+{
+ const RmgrDescData *desc = &RmgrDescTable[rmid];
+ const char *rec;
+
+ rec = psprintf("0x%x", info);
+
+ switch (rmid)
+ {
+ case RM_XLOG_ID:
+ switch (info)
+ {
+ case XLOG_CHECKPOINT_SHUTDOWN:
+ rec = "CHECKPOINT_SHUTDOWN";
+ break;
+ case XLOG_CHECKPOINT_ONLINE:
+ rec = "CHECKPOINT_ONLINE";
+ break;
+ case XLOG_NOOP:
+ rec = "NOOP";
+ break;
+ case XLOG_NEXTOID:
+ rec = "NEXTOID";
+ break;
+ case XLOG_SWITCH:
+ rec = "SWITCH";
+ break;
+ case XLOG_BACKUP_END:
+ rec = "BACKUP_END";
+ break;
+ case XLOG_PARAMETER_CHANGE:
+ rec = "PARAMETER_CHANGE";
+ break;
+ case XLOG_RESTORE_POINT:
+ rec = "RESTORE_POINT";
+ break;
+ case XLOG_FPW_CHANGE:
+ rec = "FPW_CHANGE";
+ break;
+ case XLOG_END_OF_RECOVERY:
+ rec = "END_OF_RECOVERY";
+ break;
+ case XLOG_FPI:
+ rec = "FPI";
+ break;
+ }
+ break;
+
+ case RM_XACT_ID:
+ switch (info)
+ {
+ case XLOG_XACT_COMMIT:
+ rec = "COMMIT";
+ break;
+ case XLOG_XACT_PREPARE:
+ rec = "PREPARE";
+ break;
+ case XLOG_XACT_ABORT:
+ rec = "ABORT";
+ break;
+ case XLOG_XACT_COMMIT_PREPARED:
+ rec = "COMMIT_PREPARED";
+ break;
+ case XLOG_XACT_ABORT_PREPARED:
+ rec = "ABORT_PREPARED";
+ break;
+ case XLOG_XACT_ASSIGNMENT:
+ rec = "ASSIGNMENT";
+ break;
+ case XLOG_XACT_COMMIT_COMPACT:
+ rec = "COMMIT_COMPACT";
+ break;
+ }
+ break;
+
+ case RM_SMGR_ID:
+ switch (info)
+ {
+ case XLOG_SMGR_CREATE:
+ rec = "CREATE";
+ break;
+ case XLOG_SMGR_TRUNCATE:
+ rec = "TRUNCATE";
+ break;
+ }
+ break;
+
+ case RM_CLOG_ID:
+ switch (info)
+ {
+ case CLOG_ZEROPAGE:
+ rec = "ZEROPAGE";
+ break;
+ case CLOG_TRUNCATE:
+ rec = "TRUNCATE";
+ break;
+ }
+ break;
+
+ case RM_DBASE_ID:
+ switch (info)
+ {
+ case XLOG_DBASE_CREATE:
+ rec = "CREATE";
+ break;
+ case XLOG_DBASE_DROP:
+ rec = "DROP";
+ break;
+ }
+ break;
+
+ case RM_TBLSPC_ID:
+ switch (info)
+ {
+ case XLOG_TBLSPC_CREATE:
+ rec = "CREATE";
+ break;
+ case XLOG_TBLSPC_DROP:
+ rec = "DROP";
+ break;
+ }
+ break;
+
+ case RM_MULTIXACT_ID:
+ switch (info)
+ {
+ case XLOG_MULTIXACT_ZERO_OFF_PAGE:
+ rec = "ZERO_OFF_PAGE";
+ break;
+ case XLOG_MULTIXACT_ZERO_MEM_PAGE:
+ rec = "ZERO_MEM_PAGE";
+ break;
+ case XLOG_MULTIXACT_CREATE_ID:
+ rec = "CREATE_ID";
+ break;
+ }
+ break;
+
+ case RM_RELMAP_ID:
+ switch (info)
+ {
+ case XLOG_RELMAP_UPDATE:
+ rec = "UPDATE";
+ break;
+ }
+ break;
+
+ case RM_STANDBY_ID:
+ switch (info)
+ {
+ case XLOG_STANDBY_LOCK:
+ rec = "LOCK";
+ break;
+ case XLOG_RUNNING_XACTS:
+ rec = "RUNNING_XACTS";
+ break;
+ }
+ break;
+
+ case RM_HEAP2_ID:
+ switch (info & XLOG_HEAP_OPMASK)
+ {
+ case XLOG_HEAP2_CLEAN:
+ rec = "CLEAN";
+ break;
+ case XLOG_HEAP2_FREEZE_PAGE:
+ rec = "FREEZE_PAGE";
+ break;
+ case XLOG_HEAP2_CLEANUP_INFO:
+ rec = "CLEANUP_INFO";
+ break;
+ case XLOG_HEAP2_VISIBLE:
+ rec = "VISIBLE";
+ break;
+ case XLOG_HEAP2_MULTI_INSERT:
+ rec = "MULTI_INSERT";
+ break;
+ case XLOG_HEAP2_LOCK_UPDATED:
+ rec = "LOCK_UPDATED";
+ break;
+ case XLOG_HEAP2_NEW_CID:
+ rec = "NEW_CID";
+ break;
+ case XLOG_HEAP2_REWRITE:
+ rec = "REWRITE";
+ break;
+ }
+
+ if (info & XLOG_HEAP_INIT_PAGE)
+ rec = psprintf("%s+INIT", rec);
+
+ break;
+
+ case RM_HEAP_ID:
+ switch (info & XLOG_HEAP_OPMASK)
+ {
+ case XLOG_HEAP_INSERT:
+ rec = "INSERT";
+ break;
+ case XLOG_HEAP_DELETE:
+ rec = "DELETE";
+ break;
+ case XLOG_HEAP_UPDATE:
+ rec = "UPDATE";
+ break;
+ case XLOG_HEAP_HOT_UPDATE:
+ rec = "HOT_UPDATE";
+ break;
+ case XLOG_HEAP_NEWPAGE:
+ rec = "NEWPAGE";
+ break;
+ case XLOG_HEAP_LOCK:
+ rec = "LOCK";
+ break;
+ case XLOG_HEAP_INPLACE:
+ rec = "INPLACE";
+ break;
+ }
+
+ if (info & XLOG_HEAP_INIT_PAGE)
+ rec = psprintf("%s+INIT", rec);
+
+ break;
+
+ case RM_BTREE_ID:
+ switch (info)
+ {
+ case XLOG_BTREE_INSERT_LEAF:
+ rec = "INSERT_LEAF";
+ break;
+ case XLOG_BTREE_INSERT_UPPER:
+ rec = "INSERT_UPPER";
+ break;
+ case XLOG_BTREE_INSERT_META:
+ rec = "INSERT_META";
+ break;
+ case XLOG_BTREE_SPLIT_L:
+ rec = "SPLIT_L";
+ break;
+ case XLOG_BTREE_SPLIT_R:
+ rec = "SPLIT_R";
+ break;
+ case XLOG_BTREE_SPLIT_L_ROOT:
+ rec = "SPLIT_L_ROOT";
+ break;
+ case XLOG_BTREE_SPLIT_R_ROOT:
+ rec = "SPLIT_R_ROOT";
+ break;
+ case XLOG_BTREE_VACUUM:
+ rec = "VACUUM";
+ break;
+ case XLOG_BTREE_DELETE:
+ rec = "DELETE";
+ break;
+ case XLOG_BTREE_MARK_PAGE_HALFDEAD:
+ rec = "MARK_PAGE_HALFDEAD";
+ break;
+ case XLOG_BTREE_UNLINK_PAGE:
+ rec = "UNLINK_PAGE";
+ break;
+ case XLOG_BTREE_UNLINK_PAGE_META:
+ rec = "UNLINK_PAGE_META";
+ break;
+ case XLOG_BTREE_NEWROOT:
+ rec = "NEWROOT";
+ break;
+ case XLOG_BTREE_REUSE_PAGE:
+ rec = "REUSE_PAGE";
+ break;
+ }
+ break;
+
+ case RM_HASH_ID:
+ break;
+
+ case RM_GIN_ID:
+ switch (info)
+ {
+ case XLOG_GIN_CREATE_INDEX:
+ rec = "CREATE_INDEX";
+ break;
+ case XLOG_GIN_CREATE_PTREE:
+ rec = "CREATE_PTREE";
+ break;
+ case XLOG_GIN_INSERT:
+ rec = "INSERT";
+ break;
+ case XLOG_GIN_SPLIT:
+ rec = "SPLIT";
+ break;
+ case XLOG_GIN_VACUUM_PAGE:
+ rec = "VACUUM_PAGE";
+ break;
+ case XLOG_GIN_VACUUM_DATA_LEAF_PAGE:
+ rec = "VACUUM_DATA_LEAF_PAGE";
+ break;
+ case XLOG_GIN_DELETE_PAGE:
+ rec = "DELETE_PAGE";
+ break;
+ case XLOG_GIN_UPDATE_META_PAGE:
+ rec = "UPDATE_META_PAGE";
+ break;
+ case XLOG_GIN_INSERT_LISTPAGE:
+ rec = "INSERT_LISTPAGE";
+ break;
+ case XLOG_GIN_DELETE_LISTPAGE:
+ rec = "DELETE_LISTPAGE";
+ break;
+ }
+ break;
+
+ case RM_GIST_ID:
+ switch (info)
+ {
+ case XLOG_GIST_PAGE_UPDATE:
+ rec = "PAGE_UPDATE";
+ break;
+ case XLOG_GIST_PAGE_SPLIT:
+ rec = "PAGE_SPLIT";
+ break;
+ case XLOG_GIST_CREATE_INDEX:
+ rec = "CREATE_INDEX";
+ break;
+ }
+ break;
+
+ case RM_SEQ_ID:
+ switch (info)
+ {
+ case XLOG_SEQ_LOG:
+ rec = "LOG";
+ break;
+ }
+ break;
+
+ case RM_SPGIST_ID:
+ switch (info)
+ {
+ case XLOG_SPGIST_CREATE_INDEX:
+ rec = "CREATE_INDEX";
+ break;
+ case XLOG_SPGIST_ADD_LEAF:
+ rec = "ADD_LEAF";
+ break;
+ case XLOG_SPGIST_MOVE_LEAFS:
+ rec = "MOVE_LEAFS";
+ break;
+ case XLOG_SPGIST_ADD_NODE:
+ rec = "ADD_NODE";
+ break;
+ case XLOG_SPGIST_SPLIT_TUPLE:
+ rec = "SPLIT_TUPLE";
+ break;
+ case XLOG_SPGIST_PICKSPLIT:
+ rec = "PICKSPLIT";
+ break;
+ case XLOG_SPGIST_VACUUM_LEAF:
+ rec = "VACUUM_LEAF";
+ break;
+ case XLOG_SPGIST_VACUUM_ROOT:
+ rec = "VACUUM_ROOT";
+ break;
+ case XLOG_SPGIST_VACUUM_REDIRECT:
+ rec = "VACUUM_REDIRECT";
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return psprintf("%s/%s", desc->rm_name, rec);
+}
+
+/*
+ * Display a single row of record counts and sizes for an rmgr or record.
+ */
+static void
+XLogDumpStatsRow(const char *name,
+ uint64 n, double n_pct,
+ uint64 rec_len, double rec_len_pct,
+ uint64 fpi_len, double fpi_len_pct,
+ uint64 total_len, double total_len_pct)
+{
+ printf("%-27s %20zu (%6.02f) %20zu (%6.02f) %20zu (%6.02f) %20zu (%6.02f)\n",
+ name, n, n_pct, rec_len, rec_len_pct, fpi_len, fpi_len_pct,
+ total_len, total_len_pct);
+}
+
+
+/*
+ * Display summary statistics about the records seen so far.
+ */
+static void
+XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats)
+{
+ int ri, rj;
+ uint64 total_count = 0;
+ uint64 total_rec_len = 0;
+ uint64 total_fpi_len = 0;
+ uint64 total_len = 0;
+
+ /*
+ * Make a first pass to calculate column totals:
+ * count(*),
+ * sum(xl_len+SizeOfXLogRecord),
+ * sum(xl_tot_len-xl_len-SizeOfXLogRecord), and
+ * sum(xl_tot_len).
+ * These are used to calculate percentages for each record type.
+ */
+
+ for (ri = 0; ri < RM_NEXT_ID; ri++)
+ {
+ total_count += stats->rmgr_stats[ri].count;
+ total_rec_len += stats->rmgr_stats[ri].rec_len;
+ total_fpi_len += stats->rmgr_stats[ri].fpi_len;
+ }
+ total_len = total_rec_len+total_fpi_len;
+
+ /*
+ * 27 is strlen("Transaction/COMMIT_PREPARED"),
+ * 20 is strlen(2^64), 8 is strlen("(100.00%)")
+ */
+
+ printf("%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n"
+ "%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n",
+ "Type", "N", "(%)", "Record size", "(%)", "FPI size", "(%)", "Combined size", "(%)",
+ "----", "-", "---", "-----------", "---", "--------", "---", "-------------", "---");
+
+ for (ri = 0; ri < RM_NEXT_ID; ri++)
+ {
+ uint64 count, rec_len, fpi_len;
+
+ if (!config->stats_per_record)
+ {
+ const RmgrDescData *desc = &RmgrDescTable[ri];
+
+ count = stats->rmgr_stats[ri].count;
+ rec_len = stats->rmgr_stats[ri].rec_len;
+ fpi_len = stats->rmgr_stats[ri].fpi_len;
+
+ XLogDumpStatsRow(desc->rm_name,
+ count, 100*(double)count/total_count,
+ rec_len, 100*(double)rec_len/total_rec_len,
+ fpi_len, 100*(double)fpi_len/total_fpi_len,
+ rec_len+fpi_len, 100*(double)(rec_len+fpi_len)/total_len);
+ }
+ else
+ {
+ for (rj = 0; rj < 16; rj++)
+ {
+ count = stats->record_stats[ri][rj].count;
+ rec_len = stats->record_stats[ri][rj].rec_len;
+ fpi_len = stats->record_stats[ri][rj].fpi_len;
+
+ /* Skip undefined combinations and ones that didn't occur */
+ if (count == 0)
+ continue;
+
+ XLogDumpStatsRow(identify_record(ri, rj << 4),
+ count, 100*(double)count/total_count,
+ rec_len, 100*(double)rec_len/total_rec_len,
+ fpi_len, 100*(double)fpi_len/total_fpi_len,
+ rec_len+fpi_len, 100*(double)(rec_len+fpi_len)/total_len);
+ }
+ }
+ }
+
+ printf("%-27s %20s %8s %20s %8s %20s %8s %20s\n",
+ "", "--------", "", "--------", "", "--------", "", "--------");
+
+ /*
+ * The percentages in earlier rows were calculated against the
+ * column total, but the ones that follow are against the row total.
+ * Note that these are displayed with a % symbol to differentiate
+ * them from the earlier ones, and are thus up to 9 characters long.
+ */
+
+ printf("%-27s %20zu %-9s%20zu %-9s%20zu %-9s%20zu %-6s\n",
+ "Total",
+ stats->count, "",
+ total_rec_len, psprintf("[%.02f%%]", 100*(double)total_rec_len/total_len),
+ total_fpi_len, psprintf("[%.02f%%]", 100*(double)total_fpi_len/total_len),
+ total_len, "[100%]");
+}
+
static void
usage(void)
{
@@ -401,6 +969,8 @@ usage(void)
printf(" (default: 1 or the value used in STARTSEG)\n");
printf(" -V, --version output version information, then exit\n");
printf(" -x, --xid=XID only show records with TransactionId XID\n");
+ printf(" -z, --stats show per-rmgr statistics\n");
+ printf(" -Z, --record-stats show per-record statistics\n");
printf(" -?, --help show this help, then exit\n");
}
@@ -412,6 +982,7 @@ main(int argc, char **argv)
XLogReaderState *xlogreader_state;
XLogDumpPrivate private;
XLogDumpConfig config;
+ XLogDumpStats stats;
XLogRecord *record;
XLogRecPtr first_record;
char *errormsg;
@@ -428,6 +999,8 @@ main(int argc, char **argv)
{"timeline", required_argument, NULL, 't'},
{"xid", required_argument, NULL, 'x'},
{"version", no_argument, NULL, 'V'},
+ {"stats", no_argument, NULL, 'z'},
+ {"record-stats", no_argument, NULL, 'Z'},
{NULL, 0, NULL, 0}
};
@@ -438,6 +1011,7 @@ main(int argc, char **argv)
memset(&private, 0, sizeof(XLogDumpPrivate));
memset(&config, 0, sizeof(XLogDumpConfig));
+ memset(&stats, 0, sizeof(XLogDumpStats));
private.timeline = 1;
private.startptr = InvalidXLogRecPtr;
@@ -451,6 +1025,8 @@ main(int argc, char **argv)
config.filter_by_rmgr = -1;
config.filter_by_xid = InvalidTransactionId;
config.filter_by_xid_enabled = false;
+ config.stats = false;
+ config.stats_per_record = false;
if (argc <= 1)
{
@@ -458,7 +1034,7 @@ main(int argc, char **argv)
goto bad_argument;
}
- while ((option = getopt_long(argc, argv, "be:?fn:p:r:s:t:Vx:",
+ while ((option = getopt_long(argc, argv, "be:?fn:p:r:s:t:Vx:zZ",
long_options, &optindex)) != -1)
{
switch (option)
@@ -551,6 +1127,13 @@ main(int argc, char **argv)
}
config.filter_by_xid_enabled = true;
break;
+ case 'z':
+ config.stats = true;
+ break;
+ case 'Z':
+ config.stats = true;
+ config.stats_per_record = true;
+ break;
default:
goto bad_argument;
}
@@ -711,7 +1294,10 @@ main(int argc, char **argv)
/* after reading the first record, continue at next one */
first_record = InvalidXLogRecPtr;
- XLogDumpDisplayRecord(&config, xlogreader_state->ReadRecPtr, record);
+ if (config.stats == true)
+ XLogDumpCountRecord(&config, &stats, xlogreader_state->ReadRecPtr, record);
+ else
+ XLogDumpDisplayRecord(&config, xlogreader_state->ReadRecPtr, record);
/* check whether we printed enough */
if (config.stop_after_records > 0 &&
@@ -719,6 +1305,9 @@ main(int argc, char **argv)
break;
}
+ if (config.stats == true)
+ XLogDumpDisplayStats(&config, &stats);
+
if (errormsg)
fatal_error("error in WAL record at %X/%X: %s\n",
(uint32) (xlogreader_state->ReadRecPtr >> 32),
diff --git a/doc/src/sgml/pg_xlogdump.sgml b/doc/src/sgml/pg_xlogdump.sgml
index 1d1a2ce..bfd9eb9 100644
--- a/doc/src/sgml/pg_xlogdump.sgml
+++ b/doc/src/sgml/pg_xlogdump.sgml
@@ -180,6 +180,28 @@ PostgreSQL documentation
</varlistentry>
<varlistentry>
+ <term><option>-z</option></term>
+ <term><option>--stats</option></term>
+ <listitem>
+ <para>
+ Display summary statistics (number and size of records and
+ full-page images per rmgr) instead of individual records.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-Z</option></term>
+ <term><option>--record-stats</option></term>
+ <listitem>
+ <para>
+ Display summary statistics (number and size of records and
+ full-page images) instead of individual records.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-?</></term>
<term><option>--help</></term>
<listitem>
xlogdump-stats-rmid.difftext/x-diff; charset=us-asciiDownload
diff --git a/contrib/pg_xlogdump/pg_xlogdump.c b/contrib/pg_xlogdump/pg_xlogdump.c
index 239321f..02ec9cb 100644
--- a/contrib/pg_xlogdump/pg_xlogdump.c
+++ b/contrib/pg_xlogdump/pg_xlogdump.c
@@ -15,28 +15,13 @@
#include <dirent.h>
#include <unistd.h>
-#include "access/clog.h"
-#include "access/gin_private.h"
-#include "access/gist_private.h"
-#include "access/heapam_xlog.h"
-#include "access/heapam_xlog.h"
-#include "access/multixact.h"
-#include "access/nbtree.h"
-#include "access/spgist_private.h"
-#include "access/xact.h"
-#include "access/xlog.h"
#include "access/xlogreader.h"
#include "access/transam.h"
#include "catalog/pg_control.h"
#include "catalog/storage_xlog.h"
-#include "commands/dbcommands.h"
-#include "commands/sequence.h"
-#include "commands/tablespace.h"
#include "common/fe_memutils.h"
#include "getopt_long.h"
#include "rmgrdesc.h"
-#include "storage/standby.h"
-#include "utils/relmapper.h"
static const char *progname;
@@ -457,386 +442,6 @@ XLogDumpDisplayRecord(XLogDumpConfig *config, XLogRecPtr ReadRecPtr, XLogRecord
}
/*
- * Given an xl_rmid and the high bits of xl_info, returns a string
- * describing the record type.
- */
-static const char *
-identify_record(RmgrId rmid, uint8 info)
-{
- const RmgrDescData *desc = &RmgrDescTable[rmid];
- const char *rec;
-
- rec = psprintf("0x%x", info);
-
- switch (rmid)
- {
- case RM_XLOG_ID:
- switch (info)
- {
- case XLOG_CHECKPOINT_SHUTDOWN:
- rec = "CHECKPOINT_SHUTDOWN";
- break;
- case XLOG_CHECKPOINT_ONLINE:
- rec = "CHECKPOINT_ONLINE";
- break;
- case XLOG_NOOP:
- rec = "NOOP";
- break;
- case XLOG_NEXTOID:
- rec = "NEXTOID";
- break;
- case XLOG_SWITCH:
- rec = "SWITCH";
- break;
- case XLOG_BACKUP_END:
- rec = "BACKUP_END";
- break;
- case XLOG_PARAMETER_CHANGE:
- rec = "PARAMETER_CHANGE";
- break;
- case XLOG_RESTORE_POINT:
- rec = "RESTORE_POINT";
- break;
- case XLOG_FPW_CHANGE:
- rec = "FPW_CHANGE";
- break;
- case XLOG_END_OF_RECOVERY:
- rec = "END_OF_RECOVERY";
- break;
- case XLOG_FPI:
- rec = "FPI";
- break;
- }
- break;
-
- case RM_XACT_ID:
- switch (info)
- {
- case XLOG_XACT_COMMIT:
- rec = "COMMIT";
- break;
- case XLOG_XACT_PREPARE:
- rec = "PREPARE";
- break;
- case XLOG_XACT_ABORT:
- rec = "ABORT";
- break;
- case XLOG_XACT_COMMIT_PREPARED:
- rec = "COMMIT_PREPARED";
- break;
- case XLOG_XACT_ABORT_PREPARED:
- rec = "ABORT_PREPARED";
- break;
- case XLOG_XACT_ASSIGNMENT:
- rec = "ASSIGNMENT";
- break;
- case XLOG_XACT_COMMIT_COMPACT:
- rec = "COMMIT_COMPACT";
- break;
- }
- break;
-
- case RM_SMGR_ID:
- switch (info)
- {
- case XLOG_SMGR_CREATE:
- rec = "CREATE";
- break;
- case XLOG_SMGR_TRUNCATE:
- rec = "TRUNCATE";
- break;
- }
- break;
-
- case RM_CLOG_ID:
- switch (info)
- {
- case CLOG_ZEROPAGE:
- rec = "ZEROPAGE";
- break;
- case CLOG_TRUNCATE:
- rec = "TRUNCATE";
- break;
- }
- break;
-
- case RM_DBASE_ID:
- switch (info)
- {
- case XLOG_DBASE_CREATE:
- rec = "CREATE";
- break;
- case XLOG_DBASE_DROP:
- rec = "DROP";
- break;
- }
- break;
-
- case RM_TBLSPC_ID:
- switch (info)
- {
- case XLOG_TBLSPC_CREATE:
- rec = "CREATE";
- break;
- case XLOG_TBLSPC_DROP:
- rec = "DROP";
- break;
- }
- break;
-
- case RM_MULTIXACT_ID:
- switch (info)
- {
- case XLOG_MULTIXACT_ZERO_OFF_PAGE:
- rec = "ZERO_OFF_PAGE";
- break;
- case XLOG_MULTIXACT_ZERO_MEM_PAGE:
- rec = "ZERO_MEM_PAGE";
- break;
- case XLOG_MULTIXACT_CREATE_ID:
- rec = "CREATE_ID";
- break;
- }
- break;
-
- case RM_RELMAP_ID:
- switch (info)
- {
- case XLOG_RELMAP_UPDATE:
- rec = "UPDATE";
- break;
- }
- break;
-
- case RM_STANDBY_ID:
- switch (info)
- {
- case XLOG_STANDBY_LOCK:
- rec = "LOCK";
- break;
- case XLOG_RUNNING_XACTS:
- rec = "RUNNING_XACTS";
- break;
- }
- break;
-
- case RM_HEAP2_ID:
- switch (info & XLOG_HEAP_OPMASK)
- {
- case XLOG_HEAP2_CLEAN:
- rec = "CLEAN";
- break;
- case XLOG_HEAP2_FREEZE_PAGE:
- rec = "FREEZE_PAGE";
- break;
- case XLOG_HEAP2_CLEANUP_INFO:
- rec = "CLEANUP_INFO";
- break;
- case XLOG_HEAP2_VISIBLE:
- rec = "VISIBLE";
- break;
- case XLOG_HEAP2_MULTI_INSERT:
- rec = "MULTI_INSERT";
- break;
- case XLOG_HEAP2_LOCK_UPDATED:
- rec = "LOCK_UPDATED";
- break;
- case XLOG_HEAP2_NEW_CID:
- rec = "NEW_CID";
- break;
- case XLOG_HEAP2_REWRITE:
- rec = "REWRITE";
- break;
- }
-
- if (info & XLOG_HEAP_INIT_PAGE)
- rec = psprintf("%s+INIT", rec);
-
- break;
-
- case RM_HEAP_ID:
- switch (info & XLOG_HEAP_OPMASK)
- {
- case XLOG_HEAP_INSERT:
- rec = "INSERT";
- break;
- case XLOG_HEAP_DELETE:
- rec = "DELETE";
- break;
- case XLOG_HEAP_UPDATE:
- rec = "UPDATE";
- break;
- case XLOG_HEAP_HOT_UPDATE:
- rec = "HOT_UPDATE";
- break;
- case XLOG_HEAP_NEWPAGE:
- rec = "NEWPAGE";
- break;
- case XLOG_HEAP_LOCK:
- rec = "LOCK";
- break;
- case XLOG_HEAP_INPLACE:
- rec = "INPLACE";
- break;
- }
-
- if (info & XLOG_HEAP_INIT_PAGE)
- rec = psprintf("%s+INIT", rec);
-
- break;
-
- case RM_BTREE_ID:
- switch (info)
- {
- case XLOG_BTREE_INSERT_LEAF:
- rec = "INSERT_LEAF";
- break;
- case XLOG_BTREE_INSERT_UPPER:
- rec = "INSERT_UPPER";
- break;
- case XLOG_BTREE_INSERT_META:
- rec = "INSERT_META";
- break;
- case XLOG_BTREE_SPLIT_L:
- rec = "SPLIT_L";
- break;
- case XLOG_BTREE_SPLIT_R:
- rec = "SPLIT_R";
- break;
- case XLOG_BTREE_SPLIT_L_ROOT:
- rec = "SPLIT_L_ROOT";
- break;
- case XLOG_BTREE_SPLIT_R_ROOT:
- rec = "SPLIT_R_ROOT";
- break;
- case XLOG_BTREE_VACUUM:
- rec = "VACUUM";
- break;
- case XLOG_BTREE_DELETE:
- rec = "DELETE";
- break;
- case XLOG_BTREE_MARK_PAGE_HALFDEAD:
- rec = "MARK_PAGE_HALFDEAD";
- break;
- case XLOG_BTREE_UNLINK_PAGE:
- rec = "UNLINK_PAGE";
- break;
- case XLOG_BTREE_UNLINK_PAGE_META:
- rec = "UNLINK_PAGE_META";
- break;
- case XLOG_BTREE_NEWROOT:
- rec = "NEWROOT";
- break;
- case XLOG_BTREE_REUSE_PAGE:
- rec = "REUSE_PAGE";
- break;
- }
- break;
-
- case RM_HASH_ID:
- break;
-
- case RM_GIN_ID:
- switch (info)
- {
- case XLOG_GIN_CREATE_INDEX:
- rec = "CREATE_INDEX";
- break;
- case XLOG_GIN_CREATE_PTREE:
- rec = "CREATE_PTREE";
- break;
- case XLOG_GIN_INSERT:
- rec = "INSERT";
- break;
- case XLOG_GIN_SPLIT:
- rec = "SPLIT";
- break;
- case XLOG_GIN_VACUUM_PAGE:
- rec = "VACUUM_PAGE";
- break;
- case XLOG_GIN_VACUUM_DATA_LEAF_PAGE:
- rec = "VACUUM_DATA_LEAF_PAGE";
- break;
- case XLOG_GIN_DELETE_PAGE:
- rec = "DELETE_PAGE";
- break;
- case XLOG_GIN_UPDATE_META_PAGE:
- rec = "UPDATE_META_PAGE";
- break;
- case XLOG_GIN_INSERT_LISTPAGE:
- rec = "INSERT_LISTPAGE";
- break;
- case XLOG_GIN_DELETE_LISTPAGE:
- rec = "DELETE_LISTPAGE";
- break;
- }
- break;
-
- case RM_GIST_ID:
- switch (info)
- {
- case XLOG_GIST_PAGE_UPDATE:
- rec = "PAGE_UPDATE";
- break;
- case XLOG_GIST_PAGE_SPLIT:
- rec = "PAGE_SPLIT";
- break;
- case XLOG_GIST_CREATE_INDEX:
- rec = "CREATE_INDEX";
- break;
- }
- break;
-
- case RM_SEQ_ID:
- switch (info)
- {
- case XLOG_SEQ_LOG:
- rec = "LOG";
- break;
- }
- break;
-
- case RM_SPGIST_ID:
- switch (info)
- {
- case XLOG_SPGIST_CREATE_INDEX:
- rec = "CREATE_INDEX";
- break;
- case XLOG_SPGIST_ADD_LEAF:
- rec = "ADD_LEAF";
- break;
- case XLOG_SPGIST_MOVE_LEAFS:
- rec = "MOVE_LEAFS";
- break;
- case XLOG_SPGIST_ADD_NODE:
- rec = "ADD_NODE";
- break;
- case XLOG_SPGIST_SPLIT_TUPLE:
- rec = "SPLIT_TUPLE";
- break;
- case XLOG_SPGIST_PICKSPLIT:
- rec = "PICKSPLIT";
- break;
- case XLOG_SPGIST_VACUUM_LEAF:
- rec = "VACUUM_LEAF";
- break;
- case XLOG_SPGIST_VACUUM_ROOT:
- rec = "VACUUM_ROOT";
- break;
- case XLOG_SPGIST_VACUUM_REDIRECT:
- rec = "VACUUM_REDIRECT";
- break;
- }
- break;
-
- default:
- break;
- }
-
- return psprintf("%s/%s", desc->rm_name, rec);
-}
-
-/*
* Display a single row of record counts and sizes for an rmgr or record.
*/
static void
@@ -894,11 +499,10 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats)
for (ri = 0; ri < RM_NEXT_ID; ri++)
{
uint64 count, rec_len, fpi_len;
+ const RmgrDescData *desc = &RmgrDescTable[ri];
if (!config->stats_per_record)
{
- const RmgrDescData *desc = &RmgrDescTable[ri];
-
count = stats->rmgr_stats[ri].count;
rec_len = stats->rmgr_stats[ri].rec_len;
fpi_len = stats->rmgr_stats[ri].fpi_len;
@@ -913,6 +517,8 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats)
{
for (rj = 0; rj < 16; rj++)
{
+ const char *id;
+
count = stats->record_stats[ri][rj].count;
rec_len = stats->record_stats[ri][rj].rec_len;
fpi_len = stats->record_stats[ri][rj].fpi_len;
@@ -921,7 +527,11 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats)
if (count == 0)
continue;
- XLogDumpStatsRow(identify_record(ri, rj << 4),
+ id = desc->rm_identify(rj << 4);
+ if (id == NULL)
+ id = psprintf("0x%x", rj << 4);
+
+ XLogDumpStatsRow(psprintf("%s/%s", desc->rm_name, id),
count, 100*(double)count/total_count,
rec_len, 100*(double)rec_len/total_rec_len,
fpi_len, 100*(double)fpi_len/total_fpi_len,
diff --git a/contrib/pg_xlogdump/rmgrdesc.c b/contrib/pg_xlogdump/rmgrdesc.c
index cbcaaa6..dc27fd1 100644
--- a/contrib/pg_xlogdump/rmgrdesc.c
+++ b/contrib/pg_xlogdump/rmgrdesc.c
@@ -27,8 +27,8 @@
#include "storage/standby.h"
#include "utils/relmapper.h"
-#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \
- { name, desc, },
+#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \
+ { name, desc, identify, },
const RmgrDescData RmgrDescTable[RM_MAX_ID + 1] = {
#include "access/rmgrlist.h"
diff --git a/contrib/pg_xlogdump/rmgrdesc.h b/contrib/pg_xlogdump/rmgrdesc.h
index d964118..da805c5 100644
--- a/contrib/pg_xlogdump/rmgrdesc.h
+++ b/contrib/pg_xlogdump/rmgrdesc.h
@@ -14,6 +14,7 @@ typedef struct RmgrDescData
{
const char *rm_name;
void (*rm_desc) (StringInfo buf, XLogRecord *record);
+ const char *(*rm_identify) (uint8 info);
} RmgrDescData;
extern const RmgrDescData RmgrDescTable[];
diff --git a/src/backend/access/rmgrdesc/clogdesc.c b/src/backend/access/rmgrdesc/clogdesc.c
index e82baa8..08f225d 100644
--- a/src/backend/access/rmgrdesc/clogdesc.c
+++ b/src/backend/access/rmgrdesc/clogdesc.c
@@ -40,3 +40,21 @@ clog_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+clog_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case CLOG_ZEROPAGE:
+ id = "ZEROPAGE";
+ break;
+ case CLOG_TRUNCATE:
+ id = "TRUNCATE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/dbasedesc.c b/src/backend/access/rmgrdesc/dbasedesc.c
index 0230716..38f3a39 100644
--- a/src/backend/access/rmgrdesc/dbasedesc.c
+++ b/src/backend/access/rmgrdesc/dbasedesc.c
@@ -42,3 +42,21 @@ dbase_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+dbase_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_DBASE_CREATE:
+ id = "CREATE";
+ break;
+ case XLOG_DBASE_DROP:
+ id = "DROP";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/gindesc.c b/src/backend/access/rmgrdesc/gindesc.c
index 12d68d7..115ad5b 100644
--- a/src/backend/access/rmgrdesc/gindesc.c
+++ b/src/backend/access/rmgrdesc/gindesc.c
@@ -187,3 +187,45 @@ gin_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+gin_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_GIN_CREATE_INDEX:
+ id = "CREATE_INDEX";
+ break;
+ case XLOG_GIN_CREATE_PTREE:
+ id = "CREATE_PTREE";
+ break;
+ case XLOG_GIN_INSERT:
+ id = "INSERT";
+ break;
+ case XLOG_GIN_SPLIT:
+ id = "SPLIT";
+ break;
+ case XLOG_GIN_VACUUM_PAGE:
+ id = "VACUUM_PAGE";
+ break;
+ case XLOG_GIN_VACUUM_DATA_LEAF_PAGE:
+ id = "VACUUM_DATA_LEAF_PAGE";
+ break;
+ case XLOG_GIN_DELETE_PAGE:
+ id = "DELETE_PAGE";
+ break;
+ case XLOG_GIN_UPDATE_META_PAGE:
+ id = "UPDATE_META_PAGE";
+ break;
+ case XLOG_GIN_INSERT_LISTPAGE:
+ id = "INSERT_LISTPAGE";
+ break;
+ case XLOG_GIN_DELETE_LISTPAGE:
+ id = "DELETE_LISTPAGE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/gistdesc.c b/src/backend/access/rmgrdesc/gistdesc.c
index cdac496..e4f288b 100644
--- a/src/backend/access/rmgrdesc/gistdesc.c
+++ b/src/backend/access/rmgrdesc/gistdesc.c
@@ -67,3 +67,24 @@ gist_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+gist_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_GIST_PAGE_UPDATE:
+ id = "PAGE_UPDATE";
+ break;
+ case XLOG_GIST_PAGE_SPLIT:
+ id = "PAGE_SPLIT";
+ break;
+ case XLOG_GIST_CREATE_INDEX:
+ id = "CREATE_INDEX";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/hashdesc.c b/src/backend/access/rmgrdesc/hashdesc.c
index 86a0376..c58461c 100644
--- a/src/backend/access/rmgrdesc/hashdesc.c
+++ b/src/backend/access/rmgrdesc/hashdesc.c
@@ -20,3 +20,9 @@ void
hash_desc(StringInfo buf, XLogRecord *record)
{
}
+
+const char *
+hash_identify(uint8 info)
+{
+ return NULL;
+}
diff --git a/src/backend/access/rmgrdesc/heapdesc.c b/src/backend/access/rmgrdesc/heapdesc.c
index 7df18fa..e6149be 100644
--- a/src/backend/access/rmgrdesc/heapdesc.c
+++ b/src/backend/access/rmgrdesc/heapdesc.c
@@ -202,3 +202,78 @@ heap2_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+heap_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info & XLOG_HEAP_OPMASK)
+ {
+ case XLOG_HEAP_INSERT:
+ id = "INSERT";
+ break;
+ case XLOG_HEAP_DELETE:
+ id = "DELETE";
+ break;
+ case XLOG_HEAP_UPDATE:
+ id = "UPDATE";
+ break;
+ case XLOG_HEAP_HOT_UPDATE:
+ id = "HOT_UPDATE";
+ break;
+ case XLOG_HEAP_NEWPAGE:
+ id = "NEWPAGE";
+ break;
+ case XLOG_HEAP_LOCK:
+ id = "LOCK";
+ break;
+ case XLOG_HEAP_INPLACE:
+ id = "INPLACE";
+ break;
+ }
+
+ if (info & XLOG_HEAP_INIT_PAGE)
+ id = psprintf("%s+INIT", id);
+
+ return id;
+}
+
+const char *
+heap2_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info & XLOG_HEAP_OPMASK)
+ {
+ case XLOG_HEAP2_CLEAN:
+ id = "CLEAN";
+ break;
+ case XLOG_HEAP2_FREEZE_PAGE:
+ id = "FREEZE_PAGE";
+ break;
+ case XLOG_HEAP2_CLEANUP_INFO:
+ id = "CLEANUP_INFO";
+ break;
+ case XLOG_HEAP2_VISIBLE:
+ id = "VISIBLE";
+ break;
+ case XLOG_HEAP2_MULTI_INSERT:
+ id = "MULTI_INSERT";
+ break;
+ case XLOG_HEAP2_LOCK_UPDATED:
+ id = "LOCK_UPDATED";
+ break;
+ case XLOG_HEAP2_NEW_CID:
+ id = "NEW_CID";
+ break;
+ case XLOG_HEAP2_REWRITE:
+ id = "REWRITE";
+ break;
+ }
+
+ if (info & XLOG_HEAP_INIT_PAGE)
+ id = psprintf("%s+INIT", id);
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/mxactdesc.c b/src/backend/access/rmgrdesc/mxactdesc.c
index 50d9b55..d77b1c8 100644
--- a/src/backend/access/rmgrdesc/mxactdesc.c
+++ b/src/backend/access/rmgrdesc/mxactdesc.c
@@ -79,3 +79,24 @@ multixact_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+multixact_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_MULTIXACT_ZERO_OFF_PAGE:
+ id = "ZERO_OFF_PAGE";
+ break;
+ case XLOG_MULTIXACT_ZERO_MEM_PAGE:
+ id = "ZERO_MEM_PAGE";
+ break;
+ case XLOG_MULTIXACT_CREATE_ID:
+ id = "CREATE_ID";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/nbtdesc.c b/src/backend/access/rmgrdesc/nbtdesc.c
index bf3389c..821715c 100644
--- a/src/backend/access/rmgrdesc/nbtdesc.c
+++ b/src/backend/access/rmgrdesc/nbtdesc.c
@@ -172,3 +172,57 @@ btree_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+btree_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_BTREE_INSERT_LEAF:
+ id = "INSERT_LEAF";
+ break;
+ case XLOG_BTREE_INSERT_UPPER:
+ id = "INSERT_UPPER";
+ break;
+ case XLOG_BTREE_INSERT_META:
+ id = "INSERT_META";
+ break;
+ case XLOG_BTREE_SPLIT_L:
+ id = "SPLIT_L";
+ break;
+ case XLOG_BTREE_SPLIT_R:
+ id = "SPLIT_R";
+ break;
+ case XLOG_BTREE_SPLIT_L_ROOT:
+ id = "SPLIT_L_ROOT";
+ break;
+ case XLOG_BTREE_SPLIT_R_ROOT:
+ id = "SPLIT_R_ROOT";
+ break;
+ case XLOG_BTREE_VACUUM:
+ id = "VACUUM";
+ break;
+ case XLOG_BTREE_DELETE:
+ id = "DELETE";
+ break;
+ case XLOG_BTREE_MARK_PAGE_HALFDEAD:
+ id = "MARK_PAGE_HALFDEAD";
+ break;
+ case XLOG_BTREE_UNLINK_PAGE:
+ id = "UNLINK_PAGE";
+ break;
+ case XLOG_BTREE_UNLINK_PAGE_META:
+ id = "UNLINK_PAGE_META";
+ break;
+ case XLOG_BTREE_NEWROOT:
+ id = "NEWROOT";
+ break;
+ case XLOG_BTREE_REUSE_PAGE:
+ id = "REUSE_PAGE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/relmapdesc.c b/src/backend/access/rmgrdesc/relmapdesc.c
index 06fd4b3..2aebf22 100644
--- a/src/backend/access/rmgrdesc/relmapdesc.c
+++ b/src/backend/access/rmgrdesc/relmapdesc.c
@@ -32,3 +32,18 @@ relmap_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+relmap_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_RELMAP_UPDATE:
+ id = "UPDATE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/seqdesc.c b/src/backend/access/rmgrdesc/seqdesc.c
index 42eb9b9..157c7c6 100644
--- a/src/backend/access/rmgrdesc/seqdesc.c
+++ b/src/backend/access/rmgrdesc/seqdesc.c
@@ -35,3 +35,18 @@ seq_desc(StringInfo buf, XLogRecord *record)
appendStringInfo(buf, "rel %u/%u/%u",
xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
}
+
+const char *
+seq_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_SEQ_LOG:
+ id = "LOG";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/smgrdesc.c b/src/backend/access/rmgrdesc/smgrdesc.c
index c76c815..0a7a6e2 100644
--- a/src/backend/access/rmgrdesc/smgrdesc.c
+++ b/src/backend/access/rmgrdesc/smgrdesc.c
@@ -44,3 +44,21 @@ smgr_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+smgr_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_SMGR_CREATE:
+ id = "CREATE";
+ break;
+ case XLOG_SMGR_TRUNCATE:
+ id = "TRUNCATE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/spgdesc.c b/src/backend/access/rmgrdesc/spgdesc.c
index ed369b2..76f43ff 100644
--- a/src/backend/access/rmgrdesc/spgdesc.c
+++ b/src/backend/access/rmgrdesc/spgdesc.c
@@ -88,3 +88,42 @@ spg_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+spg_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_SPGIST_CREATE_INDEX:
+ id = "CREATE_INDEX";
+ break;
+ case XLOG_SPGIST_ADD_LEAF:
+ id = "ADD_LEAF";
+ break;
+ case XLOG_SPGIST_MOVE_LEAFS:
+ id = "MOVE_LEAFS";
+ break;
+ case XLOG_SPGIST_ADD_NODE:
+ id = "ADD_NODE";
+ break;
+ case XLOG_SPGIST_SPLIT_TUPLE:
+ id = "SPLIT_TUPLE";
+ break;
+ case XLOG_SPGIST_PICKSPLIT:
+ id = "PICKSPLIT";
+ break;
+ case XLOG_SPGIST_VACUUM_LEAF:
+ id = "VACUUM_LEAF";
+ break;
+ case XLOG_SPGIST_VACUUM_ROOT:
+ id = "VACUUM_ROOT";
+ break;
+ case XLOG_SPGIST_VACUUM_REDIRECT:
+ id = "VACUUM_REDIRECT";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/standbydesc.c b/src/backend/access/rmgrdesc/standbydesc.c
index a127d38..77503d4 100644
--- a/src/backend/access/rmgrdesc/standbydesc.c
+++ b/src/backend/access/rmgrdesc/standbydesc.c
@@ -64,3 +64,21 @@ standby_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+standby_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_STANDBY_LOCK:
+ id = "LOCK";
+ break;
+ case XLOG_RUNNING_XACTS:
+ id = "RUNNING_XACTS";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/tblspcdesc.c b/src/backend/access/rmgrdesc/tblspcdesc.c
index 30b1f06..c947845 100644
--- a/src/backend/access/rmgrdesc/tblspcdesc.c
+++ b/src/backend/access/rmgrdesc/tblspcdesc.c
@@ -39,3 +39,21 @@ tblspc_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+tblspc_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_TBLSPC_CREATE:
+ id = "CREATE";
+ break;
+ case XLOG_TBLSPC_DROP:
+ id = "DROP";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/xactdesc.c b/src/backend/access/rmgrdesc/xactdesc.c
index 994931e..8ea10c9 100644
--- a/src/backend/access/rmgrdesc/xactdesc.c
+++ b/src/backend/access/rmgrdesc/xactdesc.c
@@ -196,3 +196,36 @@ xact_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+xact_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_XACT_COMMIT:
+ id = "COMMIT";
+ break;
+ case XLOG_XACT_PREPARE:
+ id = "PREPARE";
+ break;
+ case XLOG_XACT_ABORT:
+ id = "ABORT";
+ break;
+ case XLOG_XACT_COMMIT_PREPARED:
+ id = "COMMIT_PREPARED";
+ break;
+ case XLOG_XACT_ABORT_PREPARED:
+ id = "ABORT_PREPARED";
+ break;
+ case XLOG_XACT_ASSIGNMENT:
+ id = "ASSIGNMENT";
+ break;
+ case XLOG_XACT_COMMIT_COMPACT:
+ id = "COMMIT_COMPACT";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/xlogdesc.c b/src/backend/access/rmgrdesc/xlogdesc.c
index 2224da1..04a1f24 100644
--- a/src/backend/access/rmgrdesc/xlogdesc.c
+++ b/src/backend/access/rmgrdesc/xlogdesc.c
@@ -144,3 +144,48 @@ xlog_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+xlog_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_CHECKPOINT_SHUTDOWN:
+ id = "CHECKPOINT_SHUTDOWN";
+ break;
+ case XLOG_CHECKPOINT_ONLINE:
+ id = "CHECKPOINT_ONLINE";
+ break;
+ case XLOG_NOOP:
+ id = "NOOP";
+ break;
+ case XLOG_NEXTOID:
+ id = "NEXTOID";
+ break;
+ case XLOG_SWITCH:
+ id = "SWITCH";
+ break;
+ case XLOG_BACKUP_END:
+ id = "BACKUP_END";
+ break;
+ case XLOG_PARAMETER_CHANGE:
+ id = "PARAMETER_CHANGE";
+ break;
+ case XLOG_RESTORE_POINT:
+ id = "RESTORE_POINT";
+ break;
+ case XLOG_FPW_CHANGE:
+ id = "FPW_CHANGE";
+ break;
+ case XLOG_END_OF_RECOVERY:
+ id = "END_OF_RECOVERY";
+ break;
+ case XLOG_FPI:
+ id = "FPI";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/transam/rmgr.c b/src/backend/access/transam/rmgr.c
index c0a7a6f..2645a7a 100644
--- a/src/backend/access/transam/rmgr.c
+++ b/src/backend/access/transam/rmgr.c
@@ -25,8 +25,8 @@
#include "utils/relmapper.h"
/* must be kept in sync with RmgrData definition in xlog_internal.h */
-#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \
- { name, redo, desc, startup, cleanup },
+#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \
+ { name, redo, desc, identify, startup, cleanup },
const RmgrData RmgrTable[RM_MAX_ID + 1] = {
#include "access/rmgrlist.h"
diff --git a/src/include/access/clog.h b/src/include/access/clog.h
index be9b867..8562631 100644
--- a/src/include/access/clog.h
+++ b/src/include/access/clog.h
@@ -49,5 +49,6 @@ extern void TruncateCLOG(TransactionId oldestXact);
extern void clog_redo(XLogRecPtr lsn, XLogRecord *record);
extern void clog_desc(StringInfo buf, XLogRecord *record);
+extern const char *clog_identify(uint8 info);
#endif /* CLOG_H */
diff --git a/src/include/access/gin.h b/src/include/access/gin.h
index a0b288d..0ebecb4 100644
--- a/src/include/access/gin.h
+++ b/src/include/access/gin.h
@@ -74,6 +74,7 @@ extern void ginUpdateStats(Relation index, const GinStatsData *stats);
/* ginxlog.c */
extern void gin_redo(XLogRecPtr lsn, XLogRecord *record);
extern void gin_desc(StringInfo buf, XLogRecord *record);
+extern const char *gin_identify(uint8 info);
extern void gin_xlog_startup(void);
extern void gin_xlog_cleanup(void);
diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h
index 03e9903..879f113 100644
--- a/src/include/access/gist_private.h
+++ b/src/include/access/gist_private.h
@@ -452,6 +452,7 @@ extern SplitedPageLayout *gistSplit(Relation r, Page page, IndexTuple *itup,
/* gistxlog.c */
extern void gist_redo(XLogRecPtr lsn, XLogRecord *record);
extern void gist_desc(StringInfo buf, XLogRecord *record);
+extern const char *gist_identify(uint8 info);
extern void gist_xlog_startup(void);
extern void gist_xlog_cleanup(void);
diff --git a/src/include/access/hash.h b/src/include/access/hash.h
index 42a1d94..950c1a4 100644
--- a/src/include/access/hash.h
+++ b/src/include/access/hash.h
@@ -357,5 +357,6 @@ extern OffsetNumber _hash_binsearch_last(Page page, uint32 hash_value);
/* hash.c */
extern void hash_redo(XLogRecPtr lsn, XLogRecord *record);
extern void hash_desc(StringInfo buf, XLogRecord *record);
+extern const char *hash_identify(uint8 info);
#endif /* HASH_H */
diff --git a/src/include/access/heapam_xlog.h b/src/include/access/heapam_xlog.h
index 05beb00..0e00a11 100644
--- a/src/include/access/heapam_xlog.h
+++ b/src/include/access/heapam_xlog.h
@@ -369,8 +369,10 @@ extern void HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple,
extern void heap_redo(XLogRecPtr lsn, XLogRecord *record);
extern void heap_desc(StringInfo buf, XLogRecord *record);
+extern const char *heap_identify(uint8 info);
extern void heap2_redo(XLogRecPtr lsn, XLogRecord *record);
extern void heap2_desc(StringInfo buf, XLogRecord *record);
+extern const char *heap2_identify(uint8 info);
extern void heap_xlog_logical_rewrite(XLogRecPtr lsn, XLogRecord *r);
extern XLogRecPtr log_heap_cleanup_info(RelFileNode rnode,
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index f6d2e04..1910e7a 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -136,6 +136,7 @@ extern void multixact_twophase_postabort(TransactionId xid, uint16 info,
extern void multixact_redo(XLogRecPtr lsn, XLogRecord *record);
extern void multixact_desc(StringInfo buf, XLogRecord *record);
+extern const char *multixact_identify(uint8 info);
extern char *mxid_to_string(MultiXactId multi, int nmembers,
MultiXactMember *members);
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
index 9fa943f..90fd6d0 100644
--- a/src/include/access/nbtree.h
+++ b/src/include/access/nbtree.h
@@ -726,5 +726,6 @@ extern void _bt_leafbuild(BTSpool *btspool, BTSpool *spool2);
*/
extern void btree_redo(XLogRecPtr lsn, XLogRecord *record);
extern void btree_desc(StringInfo buf, XLogRecord *record);
+extern const char *btree_identify(uint8 info);
#endif /* NBTREE_H */
diff --git a/src/include/access/rmgr.h b/src/include/access/rmgr.h
index 1b577a2..ff7fe62 100644
--- a/src/include/access/rmgr.h
+++ b/src/include/access/rmgr.h
@@ -19,7 +19,7 @@ typedef uint8 RmgrId;
* Note: RM_MAX_ID must fit in RmgrId; widening that type will affect the XLOG
* file format.
*/
-#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \
+#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \
symname,
typedef enum RmgrIds
diff --git a/src/include/access/rmgrlist.h b/src/include/access/rmgrlist.h
index 662fb77..77d4574 100644
--- a/src/include/access/rmgrlist.h
+++ b/src/include/access/rmgrlist.h
@@ -25,20 +25,20 @@
*/
/* symbol name, textual name, redo, desc, startup, cleanup */
-PG_RMGR(RM_XLOG_ID, "XLOG", xlog_redo, xlog_desc, NULL, NULL)
-PG_RMGR(RM_XACT_ID, "Transaction", xact_redo, xact_desc, NULL, NULL)
-PG_RMGR(RM_SMGR_ID, "Storage", smgr_redo, smgr_desc, NULL, NULL)
-PG_RMGR(RM_CLOG_ID, "CLOG", clog_redo, clog_desc, NULL, NULL)
-PG_RMGR(RM_DBASE_ID, "Database", dbase_redo, dbase_desc, NULL, NULL)
-PG_RMGR(RM_TBLSPC_ID, "Tablespace", tblspc_redo, tblspc_desc, NULL, NULL)
-PG_RMGR(RM_MULTIXACT_ID, "MultiXact", multixact_redo, multixact_desc, NULL, NULL)
-PG_RMGR(RM_RELMAP_ID, "RelMap", relmap_redo, relmap_desc, NULL, NULL)
-PG_RMGR(RM_STANDBY_ID, "Standby", standby_redo, standby_desc, NULL, NULL)
-PG_RMGR(RM_HEAP2_ID, "Heap2", heap2_redo, heap2_desc, NULL, NULL)
-PG_RMGR(RM_HEAP_ID, "Heap", heap_redo, heap_desc, NULL, NULL)
-PG_RMGR(RM_BTREE_ID, "Btree", btree_redo, btree_desc, NULL, NULL)
-PG_RMGR(RM_HASH_ID, "Hash", hash_redo, hash_desc, NULL, NULL)
-PG_RMGR(RM_GIN_ID, "Gin", gin_redo, gin_desc, gin_xlog_startup, gin_xlog_cleanup)
-PG_RMGR(RM_GIST_ID, "Gist", gist_redo, gist_desc, gist_xlog_startup, gist_xlog_cleanup)
-PG_RMGR(RM_SEQ_ID, "Sequence", seq_redo, seq_desc, NULL, NULL)
-PG_RMGR(RM_SPGIST_ID, "SPGist", spg_redo, spg_desc, spg_xlog_startup, spg_xlog_cleanup)
+PG_RMGR(RM_XLOG_ID, "XLOG", xlog_redo, xlog_desc, xlog_identify, NULL, NULL)
+PG_RMGR(RM_XACT_ID, "Transaction", xact_redo, xact_desc, xact_identify, NULL, NULL)
+PG_RMGR(RM_SMGR_ID, "Storage", smgr_redo, smgr_desc, smgr_identify, NULL, NULL)
+PG_RMGR(RM_CLOG_ID, "CLOG", clog_redo, clog_desc, clog_identify, NULL, NULL)
+PG_RMGR(RM_DBASE_ID, "Database", dbase_redo, dbase_desc, dbase_identify, NULL, NULL)
+PG_RMGR(RM_TBLSPC_ID, "Tablespace", tblspc_redo, tblspc_desc, tblspc_identify, NULL, NULL)
+PG_RMGR(RM_MULTIXACT_ID, "MultiXact", multixact_redo, multixact_desc, multixact_identify, NULL, NULL)
+PG_RMGR(RM_RELMAP_ID, "RelMap", relmap_redo, relmap_desc, relmap_identify, NULL, NULL)
+PG_RMGR(RM_STANDBY_ID, "Standby", standby_redo, standby_desc, standby_identify, NULL, NULL)
+PG_RMGR(RM_HEAP2_ID, "Heap2", heap2_redo, heap2_desc, heap2_identify, NULL, NULL)
+PG_RMGR(RM_HEAP_ID, "Heap", heap_redo, heap_desc, heap_identify, NULL, NULL)
+PG_RMGR(RM_BTREE_ID, "Btree", btree_redo, btree_desc, btree_identify, NULL, NULL)
+PG_RMGR(RM_HASH_ID, "Hash", hash_redo, hash_desc, hash_identify, NULL, NULL)
+PG_RMGR(RM_GIN_ID, "Gin", gin_redo, gin_desc, gin_identify, gin_xlog_startup, gin_xlog_cleanup)
+PG_RMGR(RM_GIST_ID, "Gist", gist_redo, gist_desc, gist_identify, gist_xlog_startup, gist_xlog_cleanup)
+PG_RMGR(RM_SEQ_ID, "Sequence", seq_redo, seq_desc, seq_identify, NULL, NULL)
+PG_RMGR(RM_SPGIST_ID, "SPGist", spg_redo, spg_desc, spg_identify, spg_xlog_startup, spg_xlog_cleanup)
diff --git a/src/include/access/spgist.h b/src/include/access/spgist.h
index 7f8655c..f218a83 100644
--- a/src/include/access/spgist.h
+++ b/src/include/access/spgist.h
@@ -198,6 +198,7 @@ extern Datum spgvacuumcleanup(PG_FUNCTION_ARGS);
/* spgxlog.c */
extern void spg_redo(XLogRecPtr lsn, XLogRecord *record);
extern void spg_desc(StringInfo buf, XLogRecord *record);
+extern const char *spg_identify(uint8 info);
extern void spg_xlog_startup(void);
extern void spg_xlog_cleanup(void);
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 10ee943..ff7c426 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -257,5 +257,6 @@ extern int xactGetCommittedChildren(TransactionId **ptr);
extern void xact_redo(XLogRecPtr lsn, XLogRecord *record);
extern void xact_desc(StringInfo buf, XLogRecord *record);
+extern const char *xact_identify(uint8 info);
#endif /* XACT_H */
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 85f9cb7..e16d43c 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -299,6 +299,7 @@ extern Buffer RestoreBackupBlock(XLogRecPtr lsn, XLogRecord *record,
extern void xlog_redo(XLogRecPtr lsn, XLogRecord *record);
extern void xlog_desc(StringInfo buf, XLogRecord *record);
+extern const char *xlog_identify(uint8 info);
extern void issue_xlog_fsync(int fd, XLogSegNo segno);
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index 8c8de38..5839426 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -246,6 +246,7 @@ typedef struct RmgrData
const char *rm_name;
void (*rm_redo) (XLogRecPtr lsn, struct XLogRecord *rptr);
void (*rm_desc) (StringInfo buf, struct XLogRecord *rptr);
+ const char *(*rm_identify) (uint8 info);
void (*rm_startup) (void);
void (*rm_cleanup) (void);
} RmgrData;
diff --git a/src/include/catalog/storage_xlog.h b/src/include/catalog/storage_xlog.h
index 7081c99..5fc7235 100644
--- a/src/include/catalog/storage_xlog.h
+++ b/src/include/catalog/storage_xlog.h
@@ -45,5 +45,6 @@ extern void log_smgrcreate(RelFileNode *rnode, ForkNumber forkNum);
extern void smgr_redo(XLogRecPtr lsn, XLogRecord *record);
extern void smgr_desc(StringInfo buf, XLogRecord *record);
+extern const char *smgr_identify(uint8 info);
#endif /* STORAGE_XLOG_H */
diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h
index c2380dc..811713f 100644
--- a/src/include/commands/dbcommands.h
+++ b/src/include/commands/dbcommands.h
@@ -64,6 +64,7 @@ extern char *get_database_name(Oid dbid);
extern void dbase_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void dbase_desc(StringInfo buf, XLogRecord *rptr);
+extern const char *dbase_identify(uint8 info);
extern void check_encoding_locale_matches(int encoding, const char *collate, const char *ctype);
diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h
index 8819c00..914d155 100644
--- a/src/include/commands/sequence.h
+++ b/src/include/commands/sequence.h
@@ -78,5 +78,6 @@ extern void ResetSequenceCaches(void);
extern void seq_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void seq_desc(StringInfo buf, XLogRecord *rptr);
+extern const char *seq_identify(uint8 info);
#endif /* SEQUENCE_H */
diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h
index 073cb0d..5823bd9 100644
--- a/src/include/commands/tablespace.h
+++ b/src/include/commands/tablespace.h
@@ -58,5 +58,6 @@ extern bool directory_is_empty(const char *path);
extern void tblspc_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void tblspc_desc(StringInfo buf, XLogRecord *rptr);
+extern const char *tblspc_identify(uint8 info);
#endif /* TABLESPACE_H */
diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h
index da22fd3..1c63af5 100644
--- a/src/include/storage/standby.h
+++ b/src/include/storage/standby.h
@@ -83,6 +83,7 @@ typedef struct xl_running_xacts
/* Recovery handlers for the Standby Rmgr (RM_STANDBY_ID) */
extern void standby_redo(XLogRecPtr lsn, XLogRecord *record);
extern void standby_desc(StringInfo buf, XLogRecord *record);
+extern const char *standby_identify(uint8 info);
/*
* Declarations for GetRunningTransactionData(). Similar to Snapshots, but
diff --git a/src/include/utils/relmapper.h b/src/include/utils/relmapper.h
index 76bcf18..37937dd 100644
--- a/src/include/utils/relmapper.h
+++ b/src/include/utils/relmapper.h
@@ -60,5 +60,6 @@ extern void RelationMapInitializePhase3(void);
extern void relmap_redo(XLogRecPtr lsn, XLogRecord *record);
extern void relmap_desc(StringInfo buf, XLogRecord *record);
+extern const char *relmap_identify(uint8 info);
#endif /* RELMAPPER_H */
On 2014-07-04 14:16:42 +0530, Abhijit Menon-Sen wrote:
At 2014-07-04 08:38:17 +0000, dilip.kumar@huawei.com wrote:
Once you fix above erros, I think patch is ok from my side.
I've attached two updated patches here, including the fix to the usage
message. I'll mark this ready for committer now. (The rm_identify patch
is posted separately from the xlogdump one only to make the whole thing
easier to follow.)
I'm pretty sure that most committers would want to apply the rm_identity
part in a separate commit first. Could you make it two patches, one
introducing rm_identity, and another with xlogdump using it?
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
At 2014-07-04 10:54:08 +0200, andres@2ndquadrant.com wrote:
I'm pretty sure that most committers would want to apply the
rm_identity part in a separate commit first. Could you make it
two patches, one introducing rm_identity, and another with
xlogdump using it?
Sure, attached.
-- Abhijit
Attachments:
rmid.difftext/x-diff; charset=us-asciiDownload
diff --git a/src/backend/access/rmgrdesc/clogdesc.c b/src/backend/access/rmgrdesc/clogdesc.c
index e82baa8..08f225d 100644
--- a/src/backend/access/rmgrdesc/clogdesc.c
+++ b/src/backend/access/rmgrdesc/clogdesc.c
@@ -40,3 +40,21 @@ clog_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+clog_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case CLOG_ZEROPAGE:
+ id = "ZEROPAGE";
+ break;
+ case CLOG_TRUNCATE:
+ id = "TRUNCATE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/dbasedesc.c b/src/backend/access/rmgrdesc/dbasedesc.c
index 0230716..38f3a39 100644
--- a/src/backend/access/rmgrdesc/dbasedesc.c
+++ b/src/backend/access/rmgrdesc/dbasedesc.c
@@ -42,3 +42,21 @@ dbase_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+dbase_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_DBASE_CREATE:
+ id = "CREATE";
+ break;
+ case XLOG_DBASE_DROP:
+ id = "DROP";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/gindesc.c b/src/backend/access/rmgrdesc/gindesc.c
index 12d68d7..115ad5b 100644
--- a/src/backend/access/rmgrdesc/gindesc.c
+++ b/src/backend/access/rmgrdesc/gindesc.c
@@ -187,3 +187,45 @@ gin_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+gin_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_GIN_CREATE_INDEX:
+ id = "CREATE_INDEX";
+ break;
+ case XLOG_GIN_CREATE_PTREE:
+ id = "CREATE_PTREE";
+ break;
+ case XLOG_GIN_INSERT:
+ id = "INSERT";
+ break;
+ case XLOG_GIN_SPLIT:
+ id = "SPLIT";
+ break;
+ case XLOG_GIN_VACUUM_PAGE:
+ id = "VACUUM_PAGE";
+ break;
+ case XLOG_GIN_VACUUM_DATA_LEAF_PAGE:
+ id = "VACUUM_DATA_LEAF_PAGE";
+ break;
+ case XLOG_GIN_DELETE_PAGE:
+ id = "DELETE_PAGE";
+ break;
+ case XLOG_GIN_UPDATE_META_PAGE:
+ id = "UPDATE_META_PAGE";
+ break;
+ case XLOG_GIN_INSERT_LISTPAGE:
+ id = "INSERT_LISTPAGE";
+ break;
+ case XLOG_GIN_DELETE_LISTPAGE:
+ id = "DELETE_LISTPAGE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/gistdesc.c b/src/backend/access/rmgrdesc/gistdesc.c
index cdac496..e4f288b 100644
--- a/src/backend/access/rmgrdesc/gistdesc.c
+++ b/src/backend/access/rmgrdesc/gistdesc.c
@@ -67,3 +67,24 @@ gist_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+gist_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_GIST_PAGE_UPDATE:
+ id = "PAGE_UPDATE";
+ break;
+ case XLOG_GIST_PAGE_SPLIT:
+ id = "PAGE_SPLIT";
+ break;
+ case XLOG_GIST_CREATE_INDEX:
+ id = "CREATE_INDEX";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/hashdesc.c b/src/backend/access/rmgrdesc/hashdesc.c
index 86a0376..c58461c 100644
--- a/src/backend/access/rmgrdesc/hashdesc.c
+++ b/src/backend/access/rmgrdesc/hashdesc.c
@@ -20,3 +20,9 @@ void
hash_desc(StringInfo buf, XLogRecord *record)
{
}
+
+const char *
+hash_identify(uint8 info)
+{
+ return NULL;
+}
diff --git a/src/backend/access/rmgrdesc/heapdesc.c b/src/backend/access/rmgrdesc/heapdesc.c
index 7df18fa..e6149be 100644
--- a/src/backend/access/rmgrdesc/heapdesc.c
+++ b/src/backend/access/rmgrdesc/heapdesc.c
@@ -202,3 +202,78 @@ heap2_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+heap_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info & XLOG_HEAP_OPMASK)
+ {
+ case XLOG_HEAP_INSERT:
+ id = "INSERT";
+ break;
+ case XLOG_HEAP_DELETE:
+ id = "DELETE";
+ break;
+ case XLOG_HEAP_UPDATE:
+ id = "UPDATE";
+ break;
+ case XLOG_HEAP_HOT_UPDATE:
+ id = "HOT_UPDATE";
+ break;
+ case XLOG_HEAP_NEWPAGE:
+ id = "NEWPAGE";
+ break;
+ case XLOG_HEAP_LOCK:
+ id = "LOCK";
+ break;
+ case XLOG_HEAP_INPLACE:
+ id = "INPLACE";
+ break;
+ }
+
+ if (info & XLOG_HEAP_INIT_PAGE)
+ id = psprintf("%s+INIT", id);
+
+ return id;
+}
+
+const char *
+heap2_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info & XLOG_HEAP_OPMASK)
+ {
+ case XLOG_HEAP2_CLEAN:
+ id = "CLEAN";
+ break;
+ case XLOG_HEAP2_FREEZE_PAGE:
+ id = "FREEZE_PAGE";
+ break;
+ case XLOG_HEAP2_CLEANUP_INFO:
+ id = "CLEANUP_INFO";
+ break;
+ case XLOG_HEAP2_VISIBLE:
+ id = "VISIBLE";
+ break;
+ case XLOG_HEAP2_MULTI_INSERT:
+ id = "MULTI_INSERT";
+ break;
+ case XLOG_HEAP2_LOCK_UPDATED:
+ id = "LOCK_UPDATED";
+ break;
+ case XLOG_HEAP2_NEW_CID:
+ id = "NEW_CID";
+ break;
+ case XLOG_HEAP2_REWRITE:
+ id = "REWRITE";
+ break;
+ }
+
+ if (info & XLOG_HEAP_INIT_PAGE)
+ id = psprintf("%s+INIT", id);
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/mxactdesc.c b/src/backend/access/rmgrdesc/mxactdesc.c
index 50d9b55..d77b1c8 100644
--- a/src/backend/access/rmgrdesc/mxactdesc.c
+++ b/src/backend/access/rmgrdesc/mxactdesc.c
@@ -79,3 +79,24 @@ multixact_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+multixact_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_MULTIXACT_ZERO_OFF_PAGE:
+ id = "ZERO_OFF_PAGE";
+ break;
+ case XLOG_MULTIXACT_ZERO_MEM_PAGE:
+ id = "ZERO_MEM_PAGE";
+ break;
+ case XLOG_MULTIXACT_CREATE_ID:
+ id = "CREATE_ID";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/nbtdesc.c b/src/backend/access/rmgrdesc/nbtdesc.c
index bf3389c..821715c 100644
--- a/src/backend/access/rmgrdesc/nbtdesc.c
+++ b/src/backend/access/rmgrdesc/nbtdesc.c
@@ -172,3 +172,57 @@ btree_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+btree_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_BTREE_INSERT_LEAF:
+ id = "INSERT_LEAF";
+ break;
+ case XLOG_BTREE_INSERT_UPPER:
+ id = "INSERT_UPPER";
+ break;
+ case XLOG_BTREE_INSERT_META:
+ id = "INSERT_META";
+ break;
+ case XLOG_BTREE_SPLIT_L:
+ id = "SPLIT_L";
+ break;
+ case XLOG_BTREE_SPLIT_R:
+ id = "SPLIT_R";
+ break;
+ case XLOG_BTREE_SPLIT_L_ROOT:
+ id = "SPLIT_L_ROOT";
+ break;
+ case XLOG_BTREE_SPLIT_R_ROOT:
+ id = "SPLIT_R_ROOT";
+ break;
+ case XLOG_BTREE_VACUUM:
+ id = "VACUUM";
+ break;
+ case XLOG_BTREE_DELETE:
+ id = "DELETE";
+ break;
+ case XLOG_BTREE_MARK_PAGE_HALFDEAD:
+ id = "MARK_PAGE_HALFDEAD";
+ break;
+ case XLOG_BTREE_UNLINK_PAGE:
+ id = "UNLINK_PAGE";
+ break;
+ case XLOG_BTREE_UNLINK_PAGE_META:
+ id = "UNLINK_PAGE_META";
+ break;
+ case XLOG_BTREE_NEWROOT:
+ id = "NEWROOT";
+ break;
+ case XLOG_BTREE_REUSE_PAGE:
+ id = "REUSE_PAGE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/relmapdesc.c b/src/backend/access/rmgrdesc/relmapdesc.c
index 06fd4b3..2aebf22 100644
--- a/src/backend/access/rmgrdesc/relmapdesc.c
+++ b/src/backend/access/rmgrdesc/relmapdesc.c
@@ -32,3 +32,18 @@ relmap_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+relmap_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_RELMAP_UPDATE:
+ id = "UPDATE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/seqdesc.c b/src/backend/access/rmgrdesc/seqdesc.c
index 42eb9b9..157c7c6 100644
--- a/src/backend/access/rmgrdesc/seqdesc.c
+++ b/src/backend/access/rmgrdesc/seqdesc.c
@@ -35,3 +35,18 @@ seq_desc(StringInfo buf, XLogRecord *record)
appendStringInfo(buf, "rel %u/%u/%u",
xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
}
+
+const char *
+seq_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_SEQ_LOG:
+ id = "LOG";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/smgrdesc.c b/src/backend/access/rmgrdesc/smgrdesc.c
index c76c815..0a7a6e2 100644
--- a/src/backend/access/rmgrdesc/smgrdesc.c
+++ b/src/backend/access/rmgrdesc/smgrdesc.c
@@ -44,3 +44,21 @@ smgr_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+smgr_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_SMGR_CREATE:
+ id = "CREATE";
+ break;
+ case XLOG_SMGR_TRUNCATE:
+ id = "TRUNCATE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/spgdesc.c b/src/backend/access/rmgrdesc/spgdesc.c
index ed369b2..76f43ff 100644
--- a/src/backend/access/rmgrdesc/spgdesc.c
+++ b/src/backend/access/rmgrdesc/spgdesc.c
@@ -88,3 +88,42 @@ spg_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+spg_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_SPGIST_CREATE_INDEX:
+ id = "CREATE_INDEX";
+ break;
+ case XLOG_SPGIST_ADD_LEAF:
+ id = "ADD_LEAF";
+ break;
+ case XLOG_SPGIST_MOVE_LEAFS:
+ id = "MOVE_LEAFS";
+ break;
+ case XLOG_SPGIST_ADD_NODE:
+ id = "ADD_NODE";
+ break;
+ case XLOG_SPGIST_SPLIT_TUPLE:
+ id = "SPLIT_TUPLE";
+ break;
+ case XLOG_SPGIST_PICKSPLIT:
+ id = "PICKSPLIT";
+ break;
+ case XLOG_SPGIST_VACUUM_LEAF:
+ id = "VACUUM_LEAF";
+ break;
+ case XLOG_SPGIST_VACUUM_ROOT:
+ id = "VACUUM_ROOT";
+ break;
+ case XLOG_SPGIST_VACUUM_REDIRECT:
+ id = "VACUUM_REDIRECT";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/standbydesc.c b/src/backend/access/rmgrdesc/standbydesc.c
index a127d38..77503d4 100644
--- a/src/backend/access/rmgrdesc/standbydesc.c
+++ b/src/backend/access/rmgrdesc/standbydesc.c
@@ -64,3 +64,21 @@ standby_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+standby_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_STANDBY_LOCK:
+ id = "LOCK";
+ break;
+ case XLOG_RUNNING_XACTS:
+ id = "RUNNING_XACTS";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/tblspcdesc.c b/src/backend/access/rmgrdesc/tblspcdesc.c
index 30b1f06..c947845 100644
--- a/src/backend/access/rmgrdesc/tblspcdesc.c
+++ b/src/backend/access/rmgrdesc/tblspcdesc.c
@@ -39,3 +39,21 @@ tblspc_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+tblspc_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_TBLSPC_CREATE:
+ id = "CREATE";
+ break;
+ case XLOG_TBLSPC_DROP:
+ id = "DROP";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/xactdesc.c b/src/backend/access/rmgrdesc/xactdesc.c
index 994931e..8ea10c9 100644
--- a/src/backend/access/rmgrdesc/xactdesc.c
+++ b/src/backend/access/rmgrdesc/xactdesc.c
@@ -196,3 +196,36 @@ xact_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+xact_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_XACT_COMMIT:
+ id = "COMMIT";
+ break;
+ case XLOG_XACT_PREPARE:
+ id = "PREPARE";
+ break;
+ case XLOG_XACT_ABORT:
+ id = "ABORT";
+ break;
+ case XLOG_XACT_COMMIT_PREPARED:
+ id = "COMMIT_PREPARED";
+ break;
+ case XLOG_XACT_ABORT_PREPARED:
+ id = "ABORT_PREPARED";
+ break;
+ case XLOG_XACT_ASSIGNMENT:
+ id = "ASSIGNMENT";
+ break;
+ case XLOG_XACT_COMMIT_COMPACT:
+ id = "COMMIT_COMPACT";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/xlogdesc.c b/src/backend/access/rmgrdesc/xlogdesc.c
index 2224da1..04a1f24 100644
--- a/src/backend/access/rmgrdesc/xlogdesc.c
+++ b/src/backend/access/rmgrdesc/xlogdesc.c
@@ -144,3 +144,48 @@ xlog_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+xlog_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_CHECKPOINT_SHUTDOWN:
+ id = "CHECKPOINT_SHUTDOWN";
+ break;
+ case XLOG_CHECKPOINT_ONLINE:
+ id = "CHECKPOINT_ONLINE";
+ break;
+ case XLOG_NOOP:
+ id = "NOOP";
+ break;
+ case XLOG_NEXTOID:
+ id = "NEXTOID";
+ break;
+ case XLOG_SWITCH:
+ id = "SWITCH";
+ break;
+ case XLOG_BACKUP_END:
+ id = "BACKUP_END";
+ break;
+ case XLOG_PARAMETER_CHANGE:
+ id = "PARAMETER_CHANGE";
+ break;
+ case XLOG_RESTORE_POINT:
+ id = "RESTORE_POINT";
+ break;
+ case XLOG_FPW_CHANGE:
+ id = "FPW_CHANGE";
+ break;
+ case XLOG_END_OF_RECOVERY:
+ id = "END_OF_RECOVERY";
+ break;
+ case XLOG_FPI:
+ id = "FPI";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/transam/rmgr.c b/src/backend/access/transam/rmgr.c
index c0a7a6f..2645a7a 100644
--- a/src/backend/access/transam/rmgr.c
+++ b/src/backend/access/transam/rmgr.c
@@ -25,8 +25,8 @@
#include "utils/relmapper.h"
/* must be kept in sync with RmgrData definition in xlog_internal.h */
-#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \
- { name, redo, desc, startup, cleanup },
+#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \
+ { name, redo, desc, identify, startup, cleanup },
const RmgrData RmgrTable[RM_MAX_ID + 1] = {
#include "access/rmgrlist.h"
diff --git a/src/include/access/clog.h b/src/include/access/clog.h
index be9b867..8562631 100644
--- a/src/include/access/clog.h
+++ b/src/include/access/clog.h
@@ -49,5 +49,6 @@ extern void TruncateCLOG(TransactionId oldestXact);
extern void clog_redo(XLogRecPtr lsn, XLogRecord *record);
extern void clog_desc(StringInfo buf, XLogRecord *record);
+extern const char *clog_identify(uint8 info);
#endif /* CLOG_H */
diff --git a/src/include/access/gin.h b/src/include/access/gin.h
index a0b288d..0ebecb4 100644
--- a/src/include/access/gin.h
+++ b/src/include/access/gin.h
@@ -74,6 +74,7 @@ extern void ginUpdateStats(Relation index, const GinStatsData *stats);
/* ginxlog.c */
extern void gin_redo(XLogRecPtr lsn, XLogRecord *record);
extern void gin_desc(StringInfo buf, XLogRecord *record);
+extern const char *gin_identify(uint8 info);
extern void gin_xlog_startup(void);
extern void gin_xlog_cleanup(void);
diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h
index 03e9903..879f113 100644
--- a/src/include/access/gist_private.h
+++ b/src/include/access/gist_private.h
@@ -452,6 +452,7 @@ extern SplitedPageLayout *gistSplit(Relation r, Page page, IndexTuple *itup,
/* gistxlog.c */
extern void gist_redo(XLogRecPtr lsn, XLogRecord *record);
extern void gist_desc(StringInfo buf, XLogRecord *record);
+extern const char *gist_identify(uint8 info);
extern void gist_xlog_startup(void);
extern void gist_xlog_cleanup(void);
diff --git a/src/include/access/hash.h b/src/include/access/hash.h
index 42a1d94..950c1a4 100644
--- a/src/include/access/hash.h
+++ b/src/include/access/hash.h
@@ -357,5 +357,6 @@ extern OffsetNumber _hash_binsearch_last(Page page, uint32 hash_value);
/* hash.c */
extern void hash_redo(XLogRecPtr lsn, XLogRecord *record);
extern void hash_desc(StringInfo buf, XLogRecord *record);
+extern const char *hash_identify(uint8 info);
#endif /* HASH_H */
diff --git a/src/include/access/heapam_xlog.h b/src/include/access/heapam_xlog.h
index 05beb00..0e00a11 100644
--- a/src/include/access/heapam_xlog.h
+++ b/src/include/access/heapam_xlog.h
@@ -369,8 +369,10 @@ extern void HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple,
extern void heap_redo(XLogRecPtr lsn, XLogRecord *record);
extern void heap_desc(StringInfo buf, XLogRecord *record);
+extern const char *heap_identify(uint8 info);
extern void heap2_redo(XLogRecPtr lsn, XLogRecord *record);
extern void heap2_desc(StringInfo buf, XLogRecord *record);
+extern const char *heap2_identify(uint8 info);
extern void heap_xlog_logical_rewrite(XLogRecPtr lsn, XLogRecord *r);
extern XLogRecPtr log_heap_cleanup_info(RelFileNode rnode,
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index f6d2e04..1910e7a 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -136,6 +136,7 @@ extern void multixact_twophase_postabort(TransactionId xid, uint16 info,
extern void multixact_redo(XLogRecPtr lsn, XLogRecord *record);
extern void multixact_desc(StringInfo buf, XLogRecord *record);
+extern const char *multixact_identify(uint8 info);
extern char *mxid_to_string(MultiXactId multi, int nmembers,
MultiXactMember *members);
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
index 9fa943f..90fd6d0 100644
--- a/src/include/access/nbtree.h
+++ b/src/include/access/nbtree.h
@@ -726,5 +726,6 @@ extern void _bt_leafbuild(BTSpool *btspool, BTSpool *spool2);
*/
extern void btree_redo(XLogRecPtr lsn, XLogRecord *record);
extern void btree_desc(StringInfo buf, XLogRecord *record);
+extern const char *btree_identify(uint8 info);
#endif /* NBTREE_H */
diff --git a/src/include/access/rmgr.h b/src/include/access/rmgr.h
index 1b577a2..ff7fe62 100644
--- a/src/include/access/rmgr.h
+++ b/src/include/access/rmgr.h
@@ -19,7 +19,7 @@ typedef uint8 RmgrId;
* Note: RM_MAX_ID must fit in RmgrId; widening that type will affect the XLOG
* file format.
*/
-#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \
+#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \
symname,
typedef enum RmgrIds
diff --git a/src/include/access/rmgrlist.h b/src/include/access/rmgrlist.h
index 662fb77..77d4574 100644
--- a/src/include/access/rmgrlist.h
+++ b/src/include/access/rmgrlist.h
@@ -25,20 +25,20 @@
*/
/* symbol name, textual name, redo, desc, startup, cleanup */
-PG_RMGR(RM_XLOG_ID, "XLOG", xlog_redo, xlog_desc, NULL, NULL)
-PG_RMGR(RM_XACT_ID, "Transaction", xact_redo, xact_desc, NULL, NULL)
-PG_RMGR(RM_SMGR_ID, "Storage", smgr_redo, smgr_desc, NULL, NULL)
-PG_RMGR(RM_CLOG_ID, "CLOG", clog_redo, clog_desc, NULL, NULL)
-PG_RMGR(RM_DBASE_ID, "Database", dbase_redo, dbase_desc, NULL, NULL)
-PG_RMGR(RM_TBLSPC_ID, "Tablespace", tblspc_redo, tblspc_desc, NULL, NULL)
-PG_RMGR(RM_MULTIXACT_ID, "MultiXact", multixact_redo, multixact_desc, NULL, NULL)
-PG_RMGR(RM_RELMAP_ID, "RelMap", relmap_redo, relmap_desc, NULL, NULL)
-PG_RMGR(RM_STANDBY_ID, "Standby", standby_redo, standby_desc, NULL, NULL)
-PG_RMGR(RM_HEAP2_ID, "Heap2", heap2_redo, heap2_desc, NULL, NULL)
-PG_RMGR(RM_HEAP_ID, "Heap", heap_redo, heap_desc, NULL, NULL)
-PG_RMGR(RM_BTREE_ID, "Btree", btree_redo, btree_desc, NULL, NULL)
-PG_RMGR(RM_HASH_ID, "Hash", hash_redo, hash_desc, NULL, NULL)
-PG_RMGR(RM_GIN_ID, "Gin", gin_redo, gin_desc, gin_xlog_startup, gin_xlog_cleanup)
-PG_RMGR(RM_GIST_ID, "Gist", gist_redo, gist_desc, gist_xlog_startup, gist_xlog_cleanup)
-PG_RMGR(RM_SEQ_ID, "Sequence", seq_redo, seq_desc, NULL, NULL)
-PG_RMGR(RM_SPGIST_ID, "SPGist", spg_redo, spg_desc, spg_xlog_startup, spg_xlog_cleanup)
+PG_RMGR(RM_XLOG_ID, "XLOG", xlog_redo, xlog_desc, xlog_identify, NULL, NULL)
+PG_RMGR(RM_XACT_ID, "Transaction", xact_redo, xact_desc, xact_identify, NULL, NULL)
+PG_RMGR(RM_SMGR_ID, "Storage", smgr_redo, smgr_desc, smgr_identify, NULL, NULL)
+PG_RMGR(RM_CLOG_ID, "CLOG", clog_redo, clog_desc, clog_identify, NULL, NULL)
+PG_RMGR(RM_DBASE_ID, "Database", dbase_redo, dbase_desc, dbase_identify, NULL, NULL)
+PG_RMGR(RM_TBLSPC_ID, "Tablespace", tblspc_redo, tblspc_desc, tblspc_identify, NULL, NULL)
+PG_RMGR(RM_MULTIXACT_ID, "MultiXact", multixact_redo, multixact_desc, multixact_identify, NULL, NULL)
+PG_RMGR(RM_RELMAP_ID, "RelMap", relmap_redo, relmap_desc, relmap_identify, NULL, NULL)
+PG_RMGR(RM_STANDBY_ID, "Standby", standby_redo, standby_desc, standby_identify, NULL, NULL)
+PG_RMGR(RM_HEAP2_ID, "Heap2", heap2_redo, heap2_desc, heap2_identify, NULL, NULL)
+PG_RMGR(RM_HEAP_ID, "Heap", heap_redo, heap_desc, heap_identify, NULL, NULL)
+PG_RMGR(RM_BTREE_ID, "Btree", btree_redo, btree_desc, btree_identify, NULL, NULL)
+PG_RMGR(RM_HASH_ID, "Hash", hash_redo, hash_desc, hash_identify, NULL, NULL)
+PG_RMGR(RM_GIN_ID, "Gin", gin_redo, gin_desc, gin_identify, gin_xlog_startup, gin_xlog_cleanup)
+PG_RMGR(RM_GIST_ID, "Gist", gist_redo, gist_desc, gist_identify, gist_xlog_startup, gist_xlog_cleanup)
+PG_RMGR(RM_SEQ_ID, "Sequence", seq_redo, seq_desc, seq_identify, NULL, NULL)
+PG_RMGR(RM_SPGIST_ID, "SPGist", spg_redo, spg_desc, spg_identify, spg_xlog_startup, spg_xlog_cleanup)
diff --git a/src/include/access/spgist.h b/src/include/access/spgist.h
index 7f8655c..f218a83 100644
--- a/src/include/access/spgist.h
+++ b/src/include/access/spgist.h
@@ -198,6 +198,7 @@ extern Datum spgvacuumcleanup(PG_FUNCTION_ARGS);
/* spgxlog.c */
extern void spg_redo(XLogRecPtr lsn, XLogRecord *record);
extern void spg_desc(StringInfo buf, XLogRecord *record);
+extern const char *spg_identify(uint8 info);
extern void spg_xlog_startup(void);
extern void spg_xlog_cleanup(void);
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 10ee943..ff7c426 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -257,5 +257,6 @@ extern int xactGetCommittedChildren(TransactionId **ptr);
extern void xact_redo(XLogRecPtr lsn, XLogRecord *record);
extern void xact_desc(StringInfo buf, XLogRecord *record);
+extern const char *xact_identify(uint8 info);
#endif /* XACT_H */
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 85f9cb7..e16d43c 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -299,6 +299,7 @@ extern Buffer RestoreBackupBlock(XLogRecPtr lsn, XLogRecord *record,
extern void xlog_redo(XLogRecPtr lsn, XLogRecord *record);
extern void xlog_desc(StringInfo buf, XLogRecord *record);
+extern const char *xlog_identify(uint8 info);
extern void issue_xlog_fsync(int fd, XLogSegNo segno);
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index 8c8de38..5839426 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -246,6 +246,7 @@ typedef struct RmgrData
const char *rm_name;
void (*rm_redo) (XLogRecPtr lsn, struct XLogRecord *rptr);
void (*rm_desc) (StringInfo buf, struct XLogRecord *rptr);
+ const char *(*rm_identify) (uint8 info);
void (*rm_startup) (void);
void (*rm_cleanup) (void);
} RmgrData;
diff --git a/src/include/catalog/storage_xlog.h b/src/include/catalog/storage_xlog.h
index 7081c99..5fc7235 100644
--- a/src/include/catalog/storage_xlog.h
+++ b/src/include/catalog/storage_xlog.h
@@ -45,5 +45,6 @@ extern void log_smgrcreate(RelFileNode *rnode, ForkNumber forkNum);
extern void smgr_redo(XLogRecPtr lsn, XLogRecord *record);
extern void smgr_desc(StringInfo buf, XLogRecord *record);
+extern const char *smgr_identify(uint8 info);
#endif /* STORAGE_XLOG_H */
diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h
index c2380dc..811713f 100644
--- a/src/include/commands/dbcommands.h
+++ b/src/include/commands/dbcommands.h
@@ -64,6 +64,7 @@ extern char *get_database_name(Oid dbid);
extern void dbase_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void dbase_desc(StringInfo buf, XLogRecord *rptr);
+extern const char *dbase_identify(uint8 info);
extern void check_encoding_locale_matches(int encoding, const char *collate, const char *ctype);
diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h
index 8819c00..914d155 100644
--- a/src/include/commands/sequence.h
+++ b/src/include/commands/sequence.h
@@ -78,5 +78,6 @@ extern void ResetSequenceCaches(void);
extern void seq_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void seq_desc(StringInfo buf, XLogRecord *rptr);
+extern const char *seq_identify(uint8 info);
#endif /* SEQUENCE_H */
diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h
index 073cb0d..5823bd9 100644
--- a/src/include/commands/tablespace.h
+++ b/src/include/commands/tablespace.h
@@ -58,5 +58,6 @@ extern bool directory_is_empty(const char *path);
extern void tblspc_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void tblspc_desc(StringInfo buf, XLogRecord *rptr);
+extern const char *tblspc_identify(uint8 info);
#endif /* TABLESPACE_H */
diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h
index da22fd3..1c63af5 100644
--- a/src/include/storage/standby.h
+++ b/src/include/storage/standby.h
@@ -83,6 +83,7 @@ typedef struct xl_running_xacts
/* Recovery handlers for the Standby Rmgr (RM_STANDBY_ID) */
extern void standby_redo(XLogRecPtr lsn, XLogRecord *record);
extern void standby_desc(StringInfo buf, XLogRecord *record);
+extern const char *standby_identify(uint8 info);
/*
* Declarations for GetRunningTransactionData(). Similar to Snapshots, but
diff --git a/src/include/utils/relmapper.h b/src/include/utils/relmapper.h
index 76bcf18..37937dd 100644
--- a/src/include/utils/relmapper.h
+++ b/src/include/utils/relmapper.h
@@ -60,5 +60,6 @@ extern void RelationMapInitializePhase3(void);
extern void relmap_redo(XLogRecPtr lsn, XLogRecord *record);
extern void relmap_desc(StringInfo buf, XLogRecord *record);
+extern const char *relmap_identify(uint8 info);
#endif /* RELMAPPER_H */
pg_xlogdump-stats.difftext/x-diff; charset=us-asciiDownload
diff --git a/contrib/pg_xlogdump/pg_xlogdump.c b/contrib/pg_xlogdump/pg_xlogdump.c
index c555786..02ec9cb 100644
--- a/contrib/pg_xlogdump/pg_xlogdump.c
+++ b/contrib/pg_xlogdump/pg_xlogdump.c
@@ -15,9 +15,10 @@
#include <dirent.h>
#include <unistd.h>
-#include "access/xlog.h"
#include "access/xlogreader.h"
#include "access/transam.h"
+#include "catalog/pg_control.h"
+#include "catalog/storage_xlog.h"
#include "common/fe_memutils.h"
#include "getopt_long.h"
#include "rmgrdesc.h"
@@ -41,6 +42,8 @@ typedef struct XLogDumpConfig
int stop_after_records;
int already_displayed_records;
bool follow;
+ bool stats;
+ bool stats_per_record;
/* filter options */
int filter_by_rmgr;
@@ -48,6 +51,20 @@ typedef struct XLogDumpConfig
bool filter_by_xid_enabled;
} XLogDumpConfig;
+typedef struct Stats
+{
+ uint64 count;
+ uint64 rec_len;
+ uint64 fpi_len;
+} Stats;
+
+typedef struct XLogDumpStats
+{
+ uint64 count;
+ Stats rmgr_stats[RM_NEXT_ID];
+ Stats record_stats[RM_NEXT_ID][16];
+} XLogDumpStats;
+
static void
fatal_error(const char *fmt,...)
__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
@@ -322,6 +339,50 @@ XLogDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen,
}
/*
+ * Store per-rmgr and per-record statistics for a given record.
+ */
+static void
+XLogDumpCountRecord(XLogDumpConfig *config, XLogDumpStats *stats, XLogRecPtr ReadRecPtr, XLogRecord *record)
+{
+ RmgrId rmid;
+ uint8 recid;
+
+ if (config->filter_by_rmgr != -1 &&
+ config->filter_by_rmgr != record->xl_rmid)
+ return;
+
+ if (config->filter_by_xid_enabled &&
+ config->filter_by_xid != record->xl_xid)
+ return;
+
+ stats->count++;
+
+ /* Update per-rmgr statistics */
+
+ rmid = record->xl_rmid;
+
+ stats->rmgr_stats[rmid].count++;
+ stats->rmgr_stats[rmid].rec_len +=
+ record->xl_len + SizeOfXLogRecord;
+ stats->rmgr_stats[rmid].fpi_len +=
+ record->xl_tot_len - (record->xl_len + SizeOfXLogRecord);
+
+ /*
+ * Update per-record statistics, where the record is identified by a
+ * combination of the RmgrId and the upper four bits of the xl_info
+ * field (to give sixteen possible entries per RmgrId).
+ */
+
+ recid = (record->xl_info & ~XLR_INFO_MASK) >> 4;
+
+ stats->record_stats[rmid][recid].count++;
+ stats->record_stats[rmid][recid].rec_len +=
+ record->xl_len + SizeOfXLogRecord;
+ stats->record_stats[rmid][recid].fpi_len +=
+ record->xl_tot_len - (record->xl_len + SizeOfXLogRecord);
+}
+
+/*
* Print a record to stdout
*/
static void
@@ -380,6 +441,123 @@ XLogDumpDisplayRecord(XLogDumpConfig *config, XLogRecPtr ReadRecPtr, XLogRecord
}
}
+/*
+ * Display a single row of record counts and sizes for an rmgr or record.
+ */
+static void
+XLogDumpStatsRow(const char *name,
+ uint64 n, double n_pct,
+ uint64 rec_len, double rec_len_pct,
+ uint64 fpi_len, double fpi_len_pct,
+ uint64 total_len, double total_len_pct)
+{
+ printf("%-27s %20zu (%6.02f) %20zu (%6.02f) %20zu (%6.02f) %20zu (%6.02f)\n",
+ name, n, n_pct, rec_len, rec_len_pct, fpi_len, fpi_len_pct,
+ total_len, total_len_pct);
+}
+
+
+/*
+ * Display summary statistics about the records seen so far.
+ */
+static void
+XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats)
+{
+ int ri, rj;
+ uint64 total_count = 0;
+ uint64 total_rec_len = 0;
+ uint64 total_fpi_len = 0;
+ uint64 total_len = 0;
+
+ /*
+ * Make a first pass to calculate column totals:
+ * count(*),
+ * sum(xl_len+SizeOfXLogRecord),
+ * sum(xl_tot_len-xl_len-SizeOfXLogRecord), and
+ * sum(xl_tot_len).
+ * These are used to calculate percentages for each record type.
+ */
+
+ for (ri = 0; ri < RM_NEXT_ID; ri++)
+ {
+ total_count += stats->rmgr_stats[ri].count;
+ total_rec_len += stats->rmgr_stats[ri].rec_len;
+ total_fpi_len += stats->rmgr_stats[ri].fpi_len;
+ }
+ total_len = total_rec_len+total_fpi_len;
+
+ /*
+ * 27 is strlen("Transaction/COMMIT_PREPARED"),
+ * 20 is strlen(2^64), 8 is strlen("(100.00%)")
+ */
+
+ printf("%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n"
+ "%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n",
+ "Type", "N", "(%)", "Record size", "(%)", "FPI size", "(%)", "Combined size", "(%)",
+ "----", "-", "---", "-----------", "---", "--------", "---", "-------------", "---");
+
+ for (ri = 0; ri < RM_NEXT_ID; ri++)
+ {
+ uint64 count, rec_len, fpi_len;
+ const RmgrDescData *desc = &RmgrDescTable[ri];
+
+ if (!config->stats_per_record)
+ {
+ count = stats->rmgr_stats[ri].count;
+ rec_len = stats->rmgr_stats[ri].rec_len;
+ fpi_len = stats->rmgr_stats[ri].fpi_len;
+
+ XLogDumpStatsRow(desc->rm_name,
+ count, 100*(double)count/total_count,
+ rec_len, 100*(double)rec_len/total_rec_len,
+ fpi_len, 100*(double)fpi_len/total_fpi_len,
+ rec_len+fpi_len, 100*(double)(rec_len+fpi_len)/total_len);
+ }
+ else
+ {
+ for (rj = 0; rj < 16; rj++)
+ {
+ const char *id;
+
+ count = stats->record_stats[ri][rj].count;
+ rec_len = stats->record_stats[ri][rj].rec_len;
+ fpi_len = stats->record_stats[ri][rj].fpi_len;
+
+ /* Skip undefined combinations and ones that didn't occur */
+ if (count == 0)
+ continue;
+
+ id = desc->rm_identify(rj << 4);
+ if (id == NULL)
+ id = psprintf("0x%x", rj << 4);
+
+ XLogDumpStatsRow(psprintf("%s/%s", desc->rm_name, id),
+ count, 100*(double)count/total_count,
+ rec_len, 100*(double)rec_len/total_rec_len,
+ fpi_len, 100*(double)fpi_len/total_fpi_len,
+ rec_len+fpi_len, 100*(double)(rec_len+fpi_len)/total_len);
+ }
+ }
+ }
+
+ printf("%-27s %20s %8s %20s %8s %20s %8s %20s\n",
+ "", "--------", "", "--------", "", "--------", "", "--------");
+
+ /*
+ * The percentages in earlier rows were calculated against the
+ * column total, but the ones that follow are against the row total.
+ * Note that these are displayed with a % symbol to differentiate
+ * them from the earlier ones, and are thus up to 9 characters long.
+ */
+
+ printf("%-27s %20zu %-9s%20zu %-9s%20zu %-9s%20zu %-6s\n",
+ "Total",
+ stats->count, "",
+ total_rec_len, psprintf("[%.02f%%]", 100*(double)total_rec_len/total_len),
+ total_fpi_len, psprintf("[%.02f%%]", 100*(double)total_fpi_len/total_len),
+ total_len, "[100%]");
+}
+
static void
usage(void)
{
@@ -401,6 +579,8 @@ usage(void)
printf(" (default: 1 or the value used in STARTSEG)\n");
printf(" -V, --version output version information, then exit\n");
printf(" -x, --xid=XID only show records with TransactionId XID\n");
+ printf(" -z, --stats show per-rmgr statistics\n");
+ printf(" -Z, --record-stats show per-record statistics\n");
printf(" -?, --help show this help, then exit\n");
}
@@ -412,6 +592,7 @@ main(int argc, char **argv)
XLogReaderState *xlogreader_state;
XLogDumpPrivate private;
XLogDumpConfig config;
+ XLogDumpStats stats;
XLogRecord *record;
XLogRecPtr first_record;
char *errormsg;
@@ -428,6 +609,8 @@ main(int argc, char **argv)
{"timeline", required_argument, NULL, 't'},
{"xid", required_argument, NULL, 'x'},
{"version", no_argument, NULL, 'V'},
+ {"stats", no_argument, NULL, 'z'},
+ {"record-stats", no_argument, NULL, 'Z'},
{NULL, 0, NULL, 0}
};
@@ -438,6 +621,7 @@ main(int argc, char **argv)
memset(&private, 0, sizeof(XLogDumpPrivate));
memset(&config, 0, sizeof(XLogDumpConfig));
+ memset(&stats, 0, sizeof(XLogDumpStats));
private.timeline = 1;
private.startptr = InvalidXLogRecPtr;
@@ -451,6 +635,8 @@ main(int argc, char **argv)
config.filter_by_rmgr = -1;
config.filter_by_xid = InvalidTransactionId;
config.filter_by_xid_enabled = false;
+ config.stats = false;
+ config.stats_per_record = false;
if (argc <= 1)
{
@@ -458,7 +644,7 @@ main(int argc, char **argv)
goto bad_argument;
}
- while ((option = getopt_long(argc, argv, "be:?fn:p:r:s:t:Vx:",
+ while ((option = getopt_long(argc, argv, "be:?fn:p:r:s:t:Vx:zZ",
long_options, &optindex)) != -1)
{
switch (option)
@@ -551,6 +737,13 @@ main(int argc, char **argv)
}
config.filter_by_xid_enabled = true;
break;
+ case 'z':
+ config.stats = true;
+ break;
+ case 'Z':
+ config.stats = true;
+ config.stats_per_record = true;
+ break;
default:
goto bad_argument;
}
@@ -711,7 +904,10 @@ main(int argc, char **argv)
/* after reading the first record, continue at next one */
first_record = InvalidXLogRecPtr;
- XLogDumpDisplayRecord(&config, xlogreader_state->ReadRecPtr, record);
+ if (config.stats == true)
+ XLogDumpCountRecord(&config, &stats, xlogreader_state->ReadRecPtr, record);
+ else
+ XLogDumpDisplayRecord(&config, xlogreader_state->ReadRecPtr, record);
/* check whether we printed enough */
if (config.stop_after_records > 0 &&
@@ -719,6 +915,9 @@ main(int argc, char **argv)
break;
}
+ if (config.stats == true)
+ XLogDumpDisplayStats(&config, &stats);
+
if (errormsg)
fatal_error("error in WAL record at %X/%X: %s\n",
(uint32) (xlogreader_state->ReadRecPtr >> 32),
diff --git a/contrib/pg_xlogdump/rmgrdesc.c b/contrib/pg_xlogdump/rmgrdesc.c
index cbcaaa6..dc27fd1 100644
--- a/contrib/pg_xlogdump/rmgrdesc.c
+++ b/contrib/pg_xlogdump/rmgrdesc.c
@@ -27,8 +27,8 @@
#include "storage/standby.h"
#include "utils/relmapper.h"
-#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \
- { name, desc, },
+#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \
+ { name, desc, identify, },
const RmgrDescData RmgrDescTable[RM_MAX_ID + 1] = {
#include "access/rmgrlist.h"
diff --git a/contrib/pg_xlogdump/rmgrdesc.h b/contrib/pg_xlogdump/rmgrdesc.h
index d964118..da805c5 100644
--- a/contrib/pg_xlogdump/rmgrdesc.h
+++ b/contrib/pg_xlogdump/rmgrdesc.h
@@ -14,6 +14,7 @@ typedef struct RmgrDescData
{
const char *rm_name;
void (*rm_desc) (StringInfo buf, XLogRecord *record);
+ const char *(*rm_identify) (uint8 info);
} RmgrDescData;
extern const RmgrDescData RmgrDescTable[];
diff --git a/doc/src/sgml/pg_xlogdump.sgml b/doc/src/sgml/pg_xlogdump.sgml
index 1d1a2ce..bfd9eb9 100644
--- a/doc/src/sgml/pg_xlogdump.sgml
+++ b/doc/src/sgml/pg_xlogdump.sgml
@@ -180,6 +180,28 @@ PostgreSQL documentation
</varlistentry>
<varlistentry>
+ <term><option>-z</option></term>
+ <term><option>--stats</option></term>
+ <listitem>
+ <para>
+ Display summary statistics (number and size of records and
+ full-page images per rmgr) instead of individual records.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-Z</option></term>
+ <term><option>--record-stats</option></term>
+ <listitem>
+ <para>
+ Display summary statistics (number and size of records and
+ full-page images) instead of individual records.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-?</></term>
<term><option>--help</></term>
<listitem>
Hi,
On 2014-07-04 14:42:03 +0530, Abhijit Menon-Sen wrote:
Sure, attached.
+const char * +heap_identify(uint8 info) +{ + const char *id = NULL; + + switch (info & XLOG_HEAP_OPMASK) + { + case XLOG_HEAP_INSERT: + id = "INSERT"; + break; + case XLOG_HEAP_DELETE: + id = "DELETE"; + break; + case XLOG_HEAP_UPDATE: + id = "UPDATE"; + break; + case XLOG_HEAP_HOT_UPDATE: + id = "HOT_UPDATE"; + break; + case XLOG_HEAP_NEWPAGE: + id = "NEWPAGE"; + break; + case XLOG_HEAP_LOCK: + id = "LOCK"; + break; + case XLOG_HEAP_INPLACE: + id = "INPLACE"; + break; + } + + if (info & XLOG_HEAP_INIT_PAGE) + id = psprintf("%s+INIT", id); + + return id; +}
So we're leaking memory here? For --stats that could well be relevant...
+/* + * Display a single row of record counts and sizes for an rmgr or record. + */ +static void +XLogDumpStatsRow(const char *name, + uint64 n, double n_pct, + uint64 rec_len, double rec_len_pct, + uint64 fpi_len, double fpi_len_pct, + uint64 total_len, double total_len_pct) +{ + printf("%-27s %20zu (%6.02f) %20zu (%6.02f) %20zu (%6.02f) %20zu (%6.02f)\n", + name, n, n_pct, rec_len, rec_len_pct, fpi_len, fpi_len_pct, + total_len, total_len_pct); +}
This (and following locations) is going to break on 32bit platforms. %z
indicates size_t, not 64bit. I think we're going to have to redefine the
PGAC_FUNC_SNPRINTF_LONG_LONG_INT_FORMAT callsite in configure.in to
define INT64_MODIFIER='"ll/l/I64D"'
and then define
#define INT64_FORMAT "%"CppAsString(INT64_MODIFIER)"d"
#define UINT64_FORMAT "%"CppAsString(INT64_MODIFIER)"u"
in c.h based on that, or something like i. This was written blindly, so
it'd might need further work.
Then you can use INT64_MODIFIER in you format strings. Won't be pretty,
but at least it'd work...
+static void +XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats) +{
+ /* + * 27 is strlen("Transaction/COMMIT_PREPARED"), + * 20 is strlen(2^64), 8 is strlen("(100.00%)") + */
It's far from guaranteed that 27 will always suffice. I guess it's ok
because it doesn't cause bad breakage, but just some misalignment...
+ for (ri = 0; ri < RM_NEXT_ID; ri++) + { + uint64 count, rec_len, fpi_len; + const RmgrDescData *desc = &RmgrDescTable[ri]; + + if (!config->stats_per_record) + { + count = stats->rmgr_stats[ri].count; + rec_len = stats->rmgr_stats[ri].rec_len; + fpi_len = stats->rmgr_stats[ri].fpi_len; + + XLogDumpStatsRow(desc->rm_name, + count, 100*(double)count/total_count, + rec_len, 100*(double)rec_len/total_rec_len, + fpi_len, 100*(double)fpi_len/total_fpi_len, + rec_len+fpi_len, 100*(double)(rec_len+fpi_len)/total_len); + }
Many missing spaces here.
+ else + { + for (rj = 0; rj < 16; rj++) + { + const char *id; + + count = stats->record_stats[ri][rj].count; + rec_len = stats->record_stats[ri][rj].rec_len; + fpi_len = stats->record_stats[ri][rj].fpi_len; + + /* Skip undefined combinations and ones that didn't occur */ + if (count == 0) + continue; + + id = desc->rm_identify(rj << 4); + if (id == NULL) + id = psprintf("0x%x", rj << 4); + + XLogDumpStatsRow(psprintf("%s/%s", desc->rm_name, id), + count, 100*(double)count/total_count, + rec_len, 100*(double)rec_len/total_rec_len, + fpi_len, 100*(double)fpi_len/total_fpi_len, + rec_len+fpi_len, 100*(double)(rec_len+fpi_len)/total_len); + } + } + }
Some additional leaking here.
diff --git a/contrib/pg_xlogdump/rmgrdesc.c b/contrib/pg_xlogdump/rmgrdesc.c index cbcaaa6..dc27fd1 100644 --- a/contrib/pg_xlogdump/rmgrdesc.c +++ b/contrib/pg_xlogdump/rmgrdesc.c @@ -27,8 +27,8 @@ #include "storage/standby.h" #include "utils/relmapper.h"-#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \ - { name, desc, }, +#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \ + { name, desc, identify, },const RmgrDescData RmgrDescTable[RM_MAX_ID + 1] = { #include "access/rmgrlist.h" diff --git a/contrib/pg_xlogdump/rmgrdesc.h b/contrib/pg_xlogdump/rmgrdesc.h index d964118..da805c5 100644 --- a/contrib/pg_xlogdump/rmgrdesc.h +++ b/contrib/pg_xlogdump/rmgrdesc.h @@ -14,6 +14,7 @@ typedef struct RmgrDescData { const char *rm_name; void (*rm_desc) (StringInfo buf, XLogRecord *record); + const char *(*rm_identify) (uint8 info); } RmgrDescData;
Looks like that should at least partially have been in the other patch?
The old PG_RMGR looks like it wouldn't compile with the rm_identity
argument added?
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
At 2014-07-04 11:34:21 +0200, andres@2ndquadrant.com wrote:
So we're leaking memory here? For --stats that could well be
relevant...
Will fix (I think using a static buffer would be OK here).
I think we're going to have to redefine the
PGAC_FUNC_SNPRINTF_LONG_LONG_INT_FORMAT callsite in configure.in […]
OK, will do.
It's far from guaranteed that 27 will always suffice. I guess it's ok
because it doesn't cause bad breakage, but just some misalignment...
Yes, that was my thought too.
I could measure the lengths of things and align columns dynamically, but
I really doubt it's worth the effort in this case.
Many missing spaces here. […]
Some additional leaking here.
Will fix both.
Looks like that should at least partially have been in the other
patch?
Yes, sorry. Will fix.
(I'll set this back to waiting on author. Thanks for having a look.)
-- Abhijit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2014-07-04 15:34:14 +0530, Abhijit Menon-Sen wrote:
At 2014-07-04 11:34:21 +0200, andres@2ndquadrant.com wrote:
So we're leaking memory here? For --stats that could well be
relevant...Will fix (I think using a static buffer would be OK here).
In that place, yes. There there's several other places where that's
probably isn't going to work. Probably makes sense to check memory usage
after running it over a larger amount of WAL.
It's far from guaranteed that 27 will always suffice. I guess it's ok
because it doesn't cause bad breakage, but just some misalignment...Yes, that was my thought too.
I could measure the lengths of things and align columns dynamically, but
I really doubt it's worth the effort in this case.
Nah. Too much work for no gain ;)
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
I'm pretty sure that most committers would want to apply the
rm_identity part in a separate commit first. Could you make it
two patches, one introducing rm_identity, and another with
xlogdump using it?
Carp the code:
const char *
clog_identify(uint8 info)
{
switch (info)
{
case CLOG_ZEROPAGE:
return "ZEROPAGE";
case CLOG_TRUNCATE:
return "TRUNCATE";
break;
}
return NULL;
}
or
const char *
clog_identify(uint8 info)
{
if(info==CLOG_ZEROPAGE)return "ZEROPAGE";
if(info==CLOG_TRUNCATE)return "TRUNCATE";
return NULL;
}
is a bit faster than:
const char *
clog_identify(uint8 info)
{
const char *id = NULL;
switch (info)
{
case CLOG_ZEROPAGE:
id = "ZEROPAGE";
break;
case CLOG_TRUNCATE:
id = "TRUNCATE";
break;
}
return id;
}
On 2014-07-04 18:31:34 +0800, gotoschool6g wrote:
I'm pretty sure that most committers would want to apply the
rm_identity part in a separate commit first. Could you make it
two patches, one introducing rm_identity, and another with
xlogdump using it?Carp the code:
const char *
clog_identify(uint8 info)
{
switch (info)
{
case CLOG_ZEROPAGE:
return "ZEROPAGE";
case CLOG_TRUNCATE:
return "TRUNCATE";
break;
}
return NULL;
}or
const char *
clog_identify(uint8 info)
{
if(info==CLOG_ZEROPAGE)return "ZEROPAGE";
if(info==CLOG_TRUNCATE)return "TRUNCATE";
return NULL;
}is a bit faster than:
Any halfway decent compiler will not use a local variable here. Don't
think that matters much. Also the code isn't a performance bottleneck...
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
At 2014-07-04 11:34:21 +0200, andres@2ndquadrant.com wrote:
I think we're going to have to redefine the
PGAC_FUNC_SNPRINTF_LONG_LONG_INT_FORMAT callsite in configure.in to
define INT64_MODIFIER='"ll/l/I64D"'
I've attached a patch to do this, and also add INT64_MODIFIER to
pg_config.h.in: 0001-modifier.diff
I reran autoconf, and just for convenience I've attached the resulting
changes to configure: 0002-configure.diff
Then there are the rm_identify changes: 0003-rmid.diff
Finally, the xlogdump patch using INT64_MODIFIER: 0004-xlogdump.diff
I can confirm that this series applies in-order to master, and that the
result builds cleanly (including after each patch) on my machine, and
that the resulting pg_xlogdump works as expected.
NOTE: I do not know what to do about pg_config.h.win32. If someone tells
me what to do, I can submit another patch.
Some additional leaking here.
Two of the extra calls to psprintf in pg_xlogdump happen at most
RM_MAX_ID*16 (i.e. O(record-types) not O(records)) times, and the other
two happen just before exit. It would be easy to use a static buffer and
snprintf, but I don't think it's worth doing in this case.
-- Abhijit, hoping with crossed fingers to not forget attachments now.
Attachments:
0001-modifier.difftext/x-diff; charset=us-asciiDownload
diff --git a/config/c-library.m4 b/config/c-library.m4
index 8f45010..4821a61 100644
--- a/config/c-library.m4
+++ b/config/c-library.m4
@@ -221,22 +221,22 @@ HAVE_POSIX_SIGNALS=$pgac_cv_func_posix_signals
AC_SUBST(HAVE_POSIX_SIGNALS)])# PGAC_FUNC_POSIX_SIGNALS
-# PGAC_FUNC_SNPRINTF_LONG_LONG_INT_FORMAT
+# PGAC_FUNC_SNPRINTF_LONG_LONG_INT_MODIFIER
# ---------------------------------------
-# Determine which format snprintf uses for long long int. We handle
-# %lld, %qd, %I64d. The result is in shell variable
-# LONG_LONG_INT_FORMAT.
+# Determine which length modifier snprintf uses for long long int. We
+# handle ll, q, and I64. The result is in shell variable
+# LONG_LONG_INT_MODIFIER.
#
# MinGW uses '%I64d', though gcc throws an warning with -Wall,
# while '%lld' doesn't generate a warning, but doesn't work.
#
-AC_DEFUN([PGAC_FUNC_SNPRINTF_LONG_LONG_INT_FORMAT],
-[AC_MSG_CHECKING([snprintf format for long long int])
-AC_CACHE_VAL(pgac_cv_snprintf_long_long_int_format,
-[for pgac_format in '%lld' '%qd' '%I64d'; do
+AC_DEFUN([PGAC_FUNC_SNPRINTF_LONG_LONG_INT_MODIFIER],
+[AC_MSG_CHECKING([snprintf length modifier for long long int])
+AC_CACHE_VAL(pgac_cv_snprintf_long_long_int_modifier,
+[for pgac_modifier in 'll' 'q' 'I64'; do
AC_TRY_RUN([#include <stdio.h>
typedef long long int ac_int64;
-#define INT64_FORMAT "$pgac_format"
+#define INT64_FORMAT "%${pgac_modifier}d"
ac_int64 a = 20000001;
ac_int64 b = 40000005;
@@ -258,19 +258,19 @@ int does_int64_snprintf_work()
main() {
exit(! does_int64_snprintf_work());
}],
-[pgac_cv_snprintf_long_long_int_format=$pgac_format; break],
+[pgac_cv_snprintf_long_long_int_modifier=$pgac_modifier; break],
[],
-[pgac_cv_snprintf_long_long_int_format=cross; break])
+[pgac_cv_snprintf_long_long_int_modifier=cross; break])
done])dnl AC_CACHE_VAL
-LONG_LONG_INT_FORMAT=''
+LONG_LONG_INT_MODIFIER=''
-case $pgac_cv_snprintf_long_long_int_format in
+case $pgac_cv_snprintf_long_long_int_modifier in
cross) AC_MSG_RESULT([cannot test (not on host machine)]);;
- ?*) AC_MSG_RESULT([$pgac_cv_snprintf_long_long_int_format])
- LONG_LONG_INT_FORMAT=$pgac_cv_snprintf_long_long_int_format;;
+ ?*) AC_MSG_RESULT([$pgac_cv_snprintf_long_long_int_modifier])
+ LONG_LONG_INT_MODIFIER=$pgac_cv_snprintf_long_long_int_modifier;;
*) AC_MSG_RESULT(none);;
-esac])# PGAC_FUNC_SNPRINTF_LONG_LONG_INT_FORMAT
+esac])# PGAC_FUNC_SNPRINTF_LONG_LONG_INT_MODIFIER
# PGAC_FUNC_SNPRINTF_ARG_CONTROL
diff --git a/configure.in b/configure.in
index c938a5d..6afc818 100644
--- a/configure.in
+++ b/configure.in
@@ -1636,35 +1636,38 @@ fi
# If we found "long int" is 64 bits, assume snprintf handles it. If
# we found we need to use "long long int", better check. We cope with
# snprintfs that use %lld, %qd, or %I64d as the format. If none of these
-# work, fall back to our own snprintf emulation (which we know uses %lld).
+# works, fall back to our own snprintf emulation (which we know uses %lld).
if test "$HAVE_LONG_LONG_INT_64" = yes ; then
if test $pgac_need_repl_snprintf = no; then
- PGAC_FUNC_SNPRINTF_LONG_LONG_INT_FORMAT
- if test "$LONG_LONG_INT_FORMAT" = ""; then
+ PGAC_FUNC_SNPRINTF_LONG_LONG_INT_MODIFIER
+ if test "$LONG_LONG_INT_MODIFIER" = ""; then
# Force usage of our own snprintf, since system snprintf is broken
pgac_need_repl_snprintf=yes
- LONG_LONG_INT_FORMAT='%lld'
+ LONG_LONG_INT_MODIFIER='ll'
fi
else
# Here if we previously decided we needed to use our own snprintf
- LONG_LONG_INT_FORMAT='%lld'
+ LONG_LONG_INT_MODIFIER='ll'
fi
- LONG_LONG_UINT_FORMAT=`echo "$LONG_LONG_INT_FORMAT" | sed 's/d$/u/'`
- INT64_FORMAT="\"$LONG_LONG_INT_FORMAT\""
- UINT64_FORMAT="\"$LONG_LONG_UINT_FORMAT\""
else
# Here if we are not using 'long long int' at all
- INT64_FORMAT='"%ld"'
- UINT64_FORMAT='"%lu"'
+ LONG_LONG_INT_MODIFIER='l'
fi
+INT64_FORMAT="\"%${LONG_LONG_INT_MODIFIER}d\""
+UINT64_FORMAT="\"%${LONG_LONG_INT_MODIFIER}u\""
+INT64_MODIFIER="\"$LONG_LONG_INT_MODIFIER\""
+
AC_DEFINE_UNQUOTED(INT64_FORMAT, $INT64_FORMAT,
[Define to the appropriate snprintf format for 64-bit ints.])
AC_DEFINE_UNQUOTED(UINT64_FORMAT, $UINT64_FORMAT,
[Define to the appropriate snprintf format for unsigned 64-bit ints.])
+AC_DEFINE_UNQUOTED(INT64_MODIFIER, $INT64_MODIFIER,
+ [Define to the appropriate snprintf length modifier for 64-bit ints.])
+
# Also force use of our snprintf if the system's doesn't support the %z flag.
if test "$pgac_need_repl_snprintf" = no; then
PGAC_FUNC_SNPRINTF_SIZE_T_SUPPORT
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 2a40d61..b12c4c2 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -653,6 +653,9 @@
/* Define to the appropriate snprintf format for 64-bit ints. */
#undef INT64_FORMAT
+/* Define to the appropriate snprintf length modifier for 64-bit ints. */
+#undef INT64_MODIFIER
+
/* Define to 1 if `locale_t' requires <xlocale.h>. */
#undef LOCALE_T_IN_XLOCALE
0002-configure.difftext/x-diff; charset=us-asciiDownload
diff --git a/configure b/configure
index 481096c..4c651ae 100755
--- a/configure
+++ b/configure
@@ -13039,24 +13039,24 @@ fi
# If we found "long int" is 64 bits, assume snprintf handles it. If
# we found we need to use "long long int", better check. We cope with
# snprintfs that use %lld, %qd, or %I64d as the format. If none of these
-# work, fall back to our own snprintf emulation (which we know uses %lld).
+# works, fall back to our own snprintf emulation (which we know uses %lld).
if test "$HAVE_LONG_LONG_INT_64" = yes ; then
if test $pgac_need_repl_snprintf = no; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking snprintf format for long long int" >&5
-$as_echo_n "checking snprintf format for long long int... " >&6; }
-if ${pgac_cv_snprintf_long_long_int_format+:} false; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking snprintf length modifier for long long int" >&5
+$as_echo_n "checking snprintf length modifier for long long int... " >&6; }
+if ${pgac_cv_snprintf_long_long_int_modifier+:} false; then :
$as_echo_n "(cached) " >&6
else
- for pgac_format in '%lld' '%qd' '%I64d'; do
+ for pgac_modifier in 'll' 'q' 'I64'; do
if test "$cross_compiling" = yes; then :
- pgac_cv_snprintf_long_long_int_format=cross; break
+ pgac_cv_snprintf_long_long_int_modifier=cross; break
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
typedef long long int ac_int64;
-#define INT64_FORMAT "$pgac_format"
+#define INT64_FORMAT "%${pgac_modifier}d"
ac_int64 a = 20000001;
ac_int64 b = 40000005;
@@ -13080,7 +13080,7 @@ main() {
}
_ACEOF
if ac_fn_c_try_run "$LINENO"; then :
- pgac_cv_snprintf_long_long_int_format=$pgac_format; break
+ pgac_cv_snprintf_long_long_int_modifier=$pgac_modifier; break
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
@@ -13089,35 +13089,35 @@ fi
done
fi
-LONG_LONG_INT_FORMAT=''
+LONG_LONG_INT_MODIFIER=''
-case $pgac_cv_snprintf_long_long_int_format in
+case $pgac_cv_snprintf_long_long_int_modifier in
cross) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cannot test (not on host machine)" >&5
$as_echo "cannot test (not on host machine)" >&6; };;
- ?*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_snprintf_long_long_int_format" >&5
-$as_echo "$pgac_cv_snprintf_long_long_int_format" >&6; }
- LONG_LONG_INT_FORMAT=$pgac_cv_snprintf_long_long_int_format;;
+ ?*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_snprintf_long_long_int_modifier" >&5
+$as_echo "$pgac_cv_snprintf_long_long_int_modifier" >&6; }
+ LONG_LONG_INT_MODIFIER=$pgac_cv_snprintf_long_long_int_modifier;;
*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
$as_echo "none" >&6; };;
esac
- if test "$LONG_LONG_INT_FORMAT" = ""; then
+ if test "$LONG_LONG_INT_MODIFIER" = ""; then
# Force usage of our own snprintf, since system snprintf is broken
pgac_need_repl_snprintf=yes
- LONG_LONG_INT_FORMAT='%lld'
+ LONG_LONG_INT_MODIFIER='ll'
fi
else
# Here if we previously decided we needed to use our own snprintf
- LONG_LONG_INT_FORMAT='%lld'
+ LONG_LONG_INT_MODIFIER='ll'
fi
- LONG_LONG_UINT_FORMAT=`echo "$LONG_LONG_INT_FORMAT" | sed 's/d$/u/'`
- INT64_FORMAT="\"$LONG_LONG_INT_FORMAT\""
- UINT64_FORMAT="\"$LONG_LONG_UINT_FORMAT\""
else
# Here if we are not using 'long long int' at all
- INT64_FORMAT='"%ld"'
- UINT64_FORMAT='"%lu"'
+ LONG_LONG_INT_MODIFIER='l'
fi
+INT64_FORMAT="\"%${LONG_LONG_INT_MODIFIER}d\""
+UINT64_FORMAT="\"%${LONG_LONG_INT_MODIFIER}u\""
+INT64_MODIFIER="\"$LONG_LONG_INT_MODIFIER\""
+
cat >>confdefs.h <<_ACEOF
#define INT64_FORMAT $INT64_FORMAT
@@ -13130,6 +13130,12 @@ cat >>confdefs.h <<_ACEOF
_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define INT64_MODIFIER $INT64_MODIFIER
+_ACEOF
+
+
# Also force use of our snprintf if the system's doesn't support the %z flag.
if test "$pgac_need_repl_snprintf" = no; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether snprintf supports the %z modifier" >&5
0003-rmid.difftext/x-diff; charset=us-asciiDownload
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index 8c8de38..5839426 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -246,6 +246,7 @@ typedef struct RmgrData
const char *rm_name;
void (*rm_redo) (XLogRecPtr lsn, struct XLogRecord *rptr);
void (*rm_desc) (StringInfo buf, struct XLogRecord *rptr);
+ const char *(*rm_identify) (uint8 info);
void (*rm_startup) (void);
void (*rm_cleanup) (void);
} RmgrData;
diff --git a/src/include/access/rmgr.h b/src/include/access/rmgr.h
index 1b577a2..ff7fe62 100644
--- a/src/include/access/rmgr.h
+++ b/src/include/access/rmgr.h
@@ -19,7 +19,7 @@ typedef uint8 RmgrId;
* Note: RM_MAX_ID must fit in RmgrId; widening that type will affect the XLOG
* file format.
*/
-#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \
+#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \
symname,
typedef enum RmgrIds
diff --git a/src/include/access/rmgrlist.h b/src/include/access/rmgrlist.h
index 662fb77..77d4574 100644
--- a/src/include/access/rmgrlist.h
+++ b/src/include/access/rmgrlist.h
@@ -25,20 +25,20 @@
*/
/* symbol name, textual name, redo, desc, startup, cleanup */
-PG_RMGR(RM_XLOG_ID, "XLOG", xlog_redo, xlog_desc, NULL, NULL)
-PG_RMGR(RM_XACT_ID, "Transaction", xact_redo, xact_desc, NULL, NULL)
-PG_RMGR(RM_SMGR_ID, "Storage", smgr_redo, smgr_desc, NULL, NULL)
-PG_RMGR(RM_CLOG_ID, "CLOG", clog_redo, clog_desc, NULL, NULL)
-PG_RMGR(RM_DBASE_ID, "Database", dbase_redo, dbase_desc, NULL, NULL)
-PG_RMGR(RM_TBLSPC_ID, "Tablespace", tblspc_redo, tblspc_desc, NULL, NULL)
-PG_RMGR(RM_MULTIXACT_ID, "MultiXact", multixact_redo, multixact_desc, NULL, NULL)
-PG_RMGR(RM_RELMAP_ID, "RelMap", relmap_redo, relmap_desc, NULL, NULL)
-PG_RMGR(RM_STANDBY_ID, "Standby", standby_redo, standby_desc, NULL, NULL)
-PG_RMGR(RM_HEAP2_ID, "Heap2", heap2_redo, heap2_desc, NULL, NULL)
-PG_RMGR(RM_HEAP_ID, "Heap", heap_redo, heap_desc, NULL, NULL)
-PG_RMGR(RM_BTREE_ID, "Btree", btree_redo, btree_desc, NULL, NULL)
-PG_RMGR(RM_HASH_ID, "Hash", hash_redo, hash_desc, NULL, NULL)
-PG_RMGR(RM_GIN_ID, "Gin", gin_redo, gin_desc, gin_xlog_startup, gin_xlog_cleanup)
-PG_RMGR(RM_GIST_ID, "Gist", gist_redo, gist_desc, gist_xlog_startup, gist_xlog_cleanup)
-PG_RMGR(RM_SEQ_ID, "Sequence", seq_redo, seq_desc, NULL, NULL)
-PG_RMGR(RM_SPGIST_ID, "SPGist", spg_redo, spg_desc, spg_xlog_startup, spg_xlog_cleanup)
+PG_RMGR(RM_XLOG_ID, "XLOG", xlog_redo, xlog_desc, xlog_identify, NULL, NULL)
+PG_RMGR(RM_XACT_ID, "Transaction", xact_redo, xact_desc, xact_identify, NULL, NULL)
+PG_RMGR(RM_SMGR_ID, "Storage", smgr_redo, smgr_desc, smgr_identify, NULL, NULL)
+PG_RMGR(RM_CLOG_ID, "CLOG", clog_redo, clog_desc, clog_identify, NULL, NULL)
+PG_RMGR(RM_DBASE_ID, "Database", dbase_redo, dbase_desc, dbase_identify, NULL, NULL)
+PG_RMGR(RM_TBLSPC_ID, "Tablespace", tblspc_redo, tblspc_desc, tblspc_identify, NULL, NULL)
+PG_RMGR(RM_MULTIXACT_ID, "MultiXact", multixact_redo, multixact_desc, multixact_identify, NULL, NULL)
+PG_RMGR(RM_RELMAP_ID, "RelMap", relmap_redo, relmap_desc, relmap_identify, NULL, NULL)
+PG_RMGR(RM_STANDBY_ID, "Standby", standby_redo, standby_desc, standby_identify, NULL, NULL)
+PG_RMGR(RM_HEAP2_ID, "Heap2", heap2_redo, heap2_desc, heap2_identify, NULL, NULL)
+PG_RMGR(RM_HEAP_ID, "Heap", heap_redo, heap_desc, heap_identify, NULL, NULL)
+PG_RMGR(RM_BTREE_ID, "Btree", btree_redo, btree_desc, btree_identify, NULL, NULL)
+PG_RMGR(RM_HASH_ID, "Hash", hash_redo, hash_desc, hash_identify, NULL, NULL)
+PG_RMGR(RM_GIN_ID, "Gin", gin_redo, gin_desc, gin_identify, gin_xlog_startup, gin_xlog_cleanup)
+PG_RMGR(RM_GIST_ID, "Gist", gist_redo, gist_desc, gist_identify, gist_xlog_startup, gist_xlog_cleanup)
+PG_RMGR(RM_SEQ_ID, "Sequence", seq_redo, seq_desc, seq_identify, NULL, NULL)
+PG_RMGR(RM_SPGIST_ID, "SPGist", spg_redo, spg_desc, spg_identify, spg_xlog_startup, spg_xlog_cleanup)
diff --git a/contrib/pg_xlogdump/rmgrdesc.h b/contrib/pg_xlogdump/rmgrdesc.h
index d964118..da805c5 100644
--- a/contrib/pg_xlogdump/rmgrdesc.h
+++ b/contrib/pg_xlogdump/rmgrdesc.h
@@ -14,6 +14,7 @@ typedef struct RmgrDescData
{
const char *rm_name;
void (*rm_desc) (StringInfo buf, XLogRecord *record);
+ const char *(*rm_identify) (uint8 info);
} RmgrDescData;
extern const RmgrDescData RmgrDescTable[];
diff --git a/contrib/pg_xlogdump/rmgrdesc.c b/contrib/pg_xlogdump/rmgrdesc.c
index cbcaaa6..dc27fd1 100644
--- a/contrib/pg_xlogdump/rmgrdesc.c
+++ b/contrib/pg_xlogdump/rmgrdesc.c
@@ -27,8 +27,8 @@
#include "storage/standby.h"
#include "utils/relmapper.h"
-#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \
- { name, desc, },
+#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \
+ { name, desc, identify, },
const RmgrDescData RmgrDescTable[RM_MAX_ID + 1] = {
#include "access/rmgrlist.h"
diff --git a/src/backend/access/rmgrdesc/clogdesc.c b/src/backend/access/rmgrdesc/clogdesc.c
index e82baa8..08f225d 100644
--- a/src/backend/access/rmgrdesc/clogdesc.c
+++ b/src/backend/access/rmgrdesc/clogdesc.c
@@ -40,3 +40,21 @@ clog_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+clog_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case CLOG_ZEROPAGE:
+ id = "ZEROPAGE";
+ break;
+ case CLOG_TRUNCATE:
+ id = "TRUNCATE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/dbasedesc.c b/src/backend/access/rmgrdesc/dbasedesc.c
index 0230716..38f3a39 100644
--- a/src/backend/access/rmgrdesc/dbasedesc.c
+++ b/src/backend/access/rmgrdesc/dbasedesc.c
@@ -42,3 +42,21 @@ dbase_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+dbase_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_DBASE_CREATE:
+ id = "CREATE";
+ break;
+ case XLOG_DBASE_DROP:
+ id = "DROP";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/gindesc.c b/src/backend/access/rmgrdesc/gindesc.c
index 12d68d7..115ad5b 100644
--- a/src/backend/access/rmgrdesc/gindesc.c
+++ b/src/backend/access/rmgrdesc/gindesc.c
@@ -187,3 +187,45 @@ gin_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+gin_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_GIN_CREATE_INDEX:
+ id = "CREATE_INDEX";
+ break;
+ case XLOG_GIN_CREATE_PTREE:
+ id = "CREATE_PTREE";
+ break;
+ case XLOG_GIN_INSERT:
+ id = "INSERT";
+ break;
+ case XLOG_GIN_SPLIT:
+ id = "SPLIT";
+ break;
+ case XLOG_GIN_VACUUM_PAGE:
+ id = "VACUUM_PAGE";
+ break;
+ case XLOG_GIN_VACUUM_DATA_LEAF_PAGE:
+ id = "VACUUM_DATA_LEAF_PAGE";
+ break;
+ case XLOG_GIN_DELETE_PAGE:
+ id = "DELETE_PAGE";
+ break;
+ case XLOG_GIN_UPDATE_META_PAGE:
+ id = "UPDATE_META_PAGE";
+ break;
+ case XLOG_GIN_INSERT_LISTPAGE:
+ id = "INSERT_LISTPAGE";
+ break;
+ case XLOG_GIN_DELETE_LISTPAGE:
+ id = "DELETE_LISTPAGE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/gistdesc.c b/src/backend/access/rmgrdesc/gistdesc.c
index cdac496..e4f288b 100644
--- a/src/backend/access/rmgrdesc/gistdesc.c
+++ b/src/backend/access/rmgrdesc/gistdesc.c
@@ -67,3 +67,24 @@ gist_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+gist_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_GIST_PAGE_UPDATE:
+ id = "PAGE_UPDATE";
+ break;
+ case XLOG_GIST_PAGE_SPLIT:
+ id = "PAGE_SPLIT";
+ break;
+ case XLOG_GIST_CREATE_INDEX:
+ id = "CREATE_INDEX";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/hashdesc.c b/src/backend/access/rmgrdesc/hashdesc.c
index 86a0376..c58461c 100644
--- a/src/backend/access/rmgrdesc/hashdesc.c
+++ b/src/backend/access/rmgrdesc/hashdesc.c
@@ -20,3 +20,9 @@ void
hash_desc(StringInfo buf, XLogRecord *record)
{
}
+
+const char *
+hash_identify(uint8 info)
+{
+ return NULL;
+}
diff --git a/src/backend/access/rmgrdesc/heapdesc.c b/src/backend/access/rmgrdesc/heapdesc.c
index 7df18fa..74a654c 100644
--- a/src/backend/access/rmgrdesc/heapdesc.c
+++ b/src/backend/access/rmgrdesc/heapdesc.c
@@ -202,3 +202,89 @@ heap2_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+static const char *
+append_init(const char *str)
+{
+ static char x[32];
+
+ strcpy(x, str);
+ strcat(x, "+INIT");
+
+ return x;
+}
+
+const char *
+heap_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info & XLOG_HEAP_OPMASK)
+ {
+ case XLOG_HEAP_INSERT:
+ id = "INSERT";
+ break;
+ case XLOG_HEAP_DELETE:
+ id = "DELETE";
+ break;
+ case XLOG_HEAP_UPDATE:
+ id = "UPDATE";
+ break;
+ case XLOG_HEAP_HOT_UPDATE:
+ id = "HOT_UPDATE";
+ break;
+ case XLOG_HEAP_NEWPAGE:
+ id = "NEWPAGE";
+ break;
+ case XLOG_HEAP_LOCK:
+ id = "LOCK";
+ break;
+ case XLOG_HEAP_INPLACE:
+ id = "INPLACE";
+ break;
+ }
+
+ if (info & XLOG_HEAP_INIT_PAGE)
+ id = append_init(id);
+
+ return id;
+}
+
+const char *
+heap2_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info & XLOG_HEAP_OPMASK)
+ {
+ case XLOG_HEAP2_CLEAN:
+ id = "CLEAN";
+ break;
+ case XLOG_HEAP2_FREEZE_PAGE:
+ id = "FREEZE_PAGE";
+ break;
+ case XLOG_HEAP2_CLEANUP_INFO:
+ id = "CLEANUP_INFO";
+ break;
+ case XLOG_HEAP2_VISIBLE:
+ id = "VISIBLE";
+ break;
+ case XLOG_HEAP2_MULTI_INSERT:
+ id = "MULTI_INSERT";
+ break;
+ case XLOG_HEAP2_LOCK_UPDATED:
+ id = "LOCK_UPDATED";
+ break;
+ case XLOG_HEAP2_NEW_CID:
+ id = "NEW_CID";
+ break;
+ case XLOG_HEAP2_REWRITE:
+ id = "REWRITE";
+ break;
+ }
+
+ if (info & XLOG_HEAP_INIT_PAGE)
+ id = append_init(id);
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/mxactdesc.c b/src/backend/access/rmgrdesc/mxactdesc.c
index 50d9b55..d77b1c8 100644
--- a/src/backend/access/rmgrdesc/mxactdesc.c
+++ b/src/backend/access/rmgrdesc/mxactdesc.c
@@ -79,3 +79,24 @@ multixact_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+multixact_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_MULTIXACT_ZERO_OFF_PAGE:
+ id = "ZERO_OFF_PAGE";
+ break;
+ case XLOG_MULTIXACT_ZERO_MEM_PAGE:
+ id = "ZERO_MEM_PAGE";
+ break;
+ case XLOG_MULTIXACT_CREATE_ID:
+ id = "CREATE_ID";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/nbtdesc.c b/src/backend/access/rmgrdesc/nbtdesc.c
index bf3389c..821715c 100644
--- a/src/backend/access/rmgrdesc/nbtdesc.c
+++ b/src/backend/access/rmgrdesc/nbtdesc.c
@@ -172,3 +172,57 @@ btree_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+btree_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_BTREE_INSERT_LEAF:
+ id = "INSERT_LEAF";
+ break;
+ case XLOG_BTREE_INSERT_UPPER:
+ id = "INSERT_UPPER";
+ break;
+ case XLOG_BTREE_INSERT_META:
+ id = "INSERT_META";
+ break;
+ case XLOG_BTREE_SPLIT_L:
+ id = "SPLIT_L";
+ break;
+ case XLOG_BTREE_SPLIT_R:
+ id = "SPLIT_R";
+ break;
+ case XLOG_BTREE_SPLIT_L_ROOT:
+ id = "SPLIT_L_ROOT";
+ break;
+ case XLOG_BTREE_SPLIT_R_ROOT:
+ id = "SPLIT_R_ROOT";
+ break;
+ case XLOG_BTREE_VACUUM:
+ id = "VACUUM";
+ break;
+ case XLOG_BTREE_DELETE:
+ id = "DELETE";
+ break;
+ case XLOG_BTREE_MARK_PAGE_HALFDEAD:
+ id = "MARK_PAGE_HALFDEAD";
+ break;
+ case XLOG_BTREE_UNLINK_PAGE:
+ id = "UNLINK_PAGE";
+ break;
+ case XLOG_BTREE_UNLINK_PAGE_META:
+ id = "UNLINK_PAGE_META";
+ break;
+ case XLOG_BTREE_NEWROOT:
+ id = "NEWROOT";
+ break;
+ case XLOG_BTREE_REUSE_PAGE:
+ id = "REUSE_PAGE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/relmapdesc.c b/src/backend/access/rmgrdesc/relmapdesc.c
index 06fd4b3..2aebf22 100644
--- a/src/backend/access/rmgrdesc/relmapdesc.c
+++ b/src/backend/access/rmgrdesc/relmapdesc.c
@@ -32,3 +32,18 @@ relmap_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+relmap_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_RELMAP_UPDATE:
+ id = "UPDATE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/seqdesc.c b/src/backend/access/rmgrdesc/seqdesc.c
index 42eb9b9..157c7c6 100644
--- a/src/backend/access/rmgrdesc/seqdesc.c
+++ b/src/backend/access/rmgrdesc/seqdesc.c
@@ -35,3 +35,18 @@ seq_desc(StringInfo buf, XLogRecord *record)
appendStringInfo(buf, "rel %u/%u/%u",
xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
}
+
+const char *
+seq_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_SEQ_LOG:
+ id = "LOG";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/smgrdesc.c b/src/backend/access/rmgrdesc/smgrdesc.c
index c76c815..0a7a6e2 100644
--- a/src/backend/access/rmgrdesc/smgrdesc.c
+++ b/src/backend/access/rmgrdesc/smgrdesc.c
@@ -44,3 +44,21 @@ smgr_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+smgr_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_SMGR_CREATE:
+ id = "CREATE";
+ break;
+ case XLOG_SMGR_TRUNCATE:
+ id = "TRUNCATE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/spgdesc.c b/src/backend/access/rmgrdesc/spgdesc.c
index ed369b2..76f43ff 100644
--- a/src/backend/access/rmgrdesc/spgdesc.c
+++ b/src/backend/access/rmgrdesc/spgdesc.c
@@ -88,3 +88,42 @@ spg_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+spg_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_SPGIST_CREATE_INDEX:
+ id = "CREATE_INDEX";
+ break;
+ case XLOG_SPGIST_ADD_LEAF:
+ id = "ADD_LEAF";
+ break;
+ case XLOG_SPGIST_MOVE_LEAFS:
+ id = "MOVE_LEAFS";
+ break;
+ case XLOG_SPGIST_ADD_NODE:
+ id = "ADD_NODE";
+ break;
+ case XLOG_SPGIST_SPLIT_TUPLE:
+ id = "SPLIT_TUPLE";
+ break;
+ case XLOG_SPGIST_PICKSPLIT:
+ id = "PICKSPLIT";
+ break;
+ case XLOG_SPGIST_VACUUM_LEAF:
+ id = "VACUUM_LEAF";
+ break;
+ case XLOG_SPGIST_VACUUM_ROOT:
+ id = "VACUUM_ROOT";
+ break;
+ case XLOG_SPGIST_VACUUM_REDIRECT:
+ id = "VACUUM_REDIRECT";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/standbydesc.c b/src/backend/access/rmgrdesc/standbydesc.c
index a127d38..77503d4 100644
--- a/src/backend/access/rmgrdesc/standbydesc.c
+++ b/src/backend/access/rmgrdesc/standbydesc.c
@@ -64,3 +64,21 @@ standby_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+standby_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_STANDBY_LOCK:
+ id = "LOCK";
+ break;
+ case XLOG_RUNNING_XACTS:
+ id = "RUNNING_XACTS";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/tblspcdesc.c b/src/backend/access/rmgrdesc/tblspcdesc.c
index 30b1f06..c947845 100644
--- a/src/backend/access/rmgrdesc/tblspcdesc.c
+++ b/src/backend/access/rmgrdesc/tblspcdesc.c
@@ -39,3 +39,21 @@ tblspc_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+tblspc_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_TBLSPC_CREATE:
+ id = "CREATE";
+ break;
+ case XLOG_TBLSPC_DROP:
+ id = "DROP";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/xactdesc.c b/src/backend/access/rmgrdesc/xactdesc.c
index 994931e..8ea10c9 100644
--- a/src/backend/access/rmgrdesc/xactdesc.c
+++ b/src/backend/access/rmgrdesc/xactdesc.c
@@ -196,3 +196,36 @@ xact_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+xact_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_XACT_COMMIT:
+ id = "COMMIT";
+ break;
+ case XLOG_XACT_PREPARE:
+ id = "PREPARE";
+ break;
+ case XLOG_XACT_ABORT:
+ id = "ABORT";
+ break;
+ case XLOG_XACT_COMMIT_PREPARED:
+ id = "COMMIT_PREPARED";
+ break;
+ case XLOG_XACT_ABORT_PREPARED:
+ id = "ABORT_PREPARED";
+ break;
+ case XLOG_XACT_ASSIGNMENT:
+ id = "ASSIGNMENT";
+ break;
+ case XLOG_XACT_COMMIT_COMPACT:
+ id = "COMMIT_COMPACT";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/xlogdesc.c b/src/backend/access/rmgrdesc/xlogdesc.c
index 2224da1..04a1f24 100644
--- a/src/backend/access/rmgrdesc/xlogdesc.c
+++ b/src/backend/access/rmgrdesc/xlogdesc.c
@@ -144,3 +144,48 @@ xlog_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+xlog_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_CHECKPOINT_SHUTDOWN:
+ id = "CHECKPOINT_SHUTDOWN";
+ break;
+ case XLOG_CHECKPOINT_ONLINE:
+ id = "CHECKPOINT_ONLINE";
+ break;
+ case XLOG_NOOP:
+ id = "NOOP";
+ break;
+ case XLOG_NEXTOID:
+ id = "NEXTOID";
+ break;
+ case XLOG_SWITCH:
+ id = "SWITCH";
+ break;
+ case XLOG_BACKUP_END:
+ id = "BACKUP_END";
+ break;
+ case XLOG_PARAMETER_CHANGE:
+ id = "PARAMETER_CHANGE";
+ break;
+ case XLOG_RESTORE_POINT:
+ id = "RESTORE_POINT";
+ break;
+ case XLOG_FPW_CHANGE:
+ id = "FPW_CHANGE";
+ break;
+ case XLOG_END_OF_RECOVERY:
+ id = "END_OF_RECOVERY";
+ break;
+ case XLOG_FPI:
+ id = "FPI";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/transam/rmgr.c b/src/backend/access/transam/rmgr.c
index c0a7a6f..2645a7a 100644
--- a/src/backend/access/transam/rmgr.c
+++ b/src/backend/access/transam/rmgr.c
@@ -25,8 +25,8 @@
#include "utils/relmapper.h"
/* must be kept in sync with RmgrData definition in xlog_internal.h */
-#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \
- { name, redo, desc, startup, cleanup },
+#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \
+ { name, redo, desc, identify, startup, cleanup },
const RmgrData RmgrTable[RM_MAX_ID + 1] = {
#include "access/rmgrlist.h"
diff --git a/src/include/access/clog.h b/src/include/access/clog.h
index be9b867..8562631 100644
--- a/src/include/access/clog.h
+++ b/src/include/access/clog.h
@@ -49,5 +49,6 @@ extern void TruncateCLOG(TransactionId oldestXact);
extern void clog_redo(XLogRecPtr lsn, XLogRecord *record);
extern void clog_desc(StringInfo buf, XLogRecord *record);
+extern const char *clog_identify(uint8 info);
#endif /* CLOG_H */
diff --git a/src/include/access/gin.h b/src/include/access/gin.h
index a0b288d..0ebecb4 100644
--- a/src/include/access/gin.h
+++ b/src/include/access/gin.h
@@ -74,6 +74,7 @@ extern void ginUpdateStats(Relation index, const GinStatsData *stats);
/* ginxlog.c */
extern void gin_redo(XLogRecPtr lsn, XLogRecord *record);
extern void gin_desc(StringInfo buf, XLogRecord *record);
+extern const char *gin_identify(uint8 info);
extern void gin_xlog_startup(void);
extern void gin_xlog_cleanup(void);
diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h
index 03e9903..879f113 100644
--- a/src/include/access/gist_private.h
+++ b/src/include/access/gist_private.h
@@ -452,6 +452,7 @@ extern SplitedPageLayout *gistSplit(Relation r, Page page, IndexTuple *itup,
/* gistxlog.c */
extern void gist_redo(XLogRecPtr lsn, XLogRecord *record);
extern void gist_desc(StringInfo buf, XLogRecord *record);
+extern const char *gist_identify(uint8 info);
extern void gist_xlog_startup(void);
extern void gist_xlog_cleanup(void);
diff --git a/src/include/access/hash.h b/src/include/access/hash.h
index 42a1d94..950c1a4 100644
--- a/src/include/access/hash.h
+++ b/src/include/access/hash.h
@@ -357,5 +357,6 @@ extern OffsetNumber _hash_binsearch_last(Page page, uint32 hash_value);
/* hash.c */
extern void hash_redo(XLogRecPtr lsn, XLogRecord *record);
extern void hash_desc(StringInfo buf, XLogRecord *record);
+extern const char *hash_identify(uint8 info);
#endif /* HASH_H */
diff --git a/src/include/access/heapam_xlog.h b/src/include/access/heapam_xlog.h
index 05beb00..0e00a11 100644
--- a/src/include/access/heapam_xlog.h
+++ b/src/include/access/heapam_xlog.h
@@ -369,8 +369,10 @@ extern void HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple,
extern void heap_redo(XLogRecPtr lsn, XLogRecord *record);
extern void heap_desc(StringInfo buf, XLogRecord *record);
+extern const char *heap_identify(uint8 info);
extern void heap2_redo(XLogRecPtr lsn, XLogRecord *record);
extern void heap2_desc(StringInfo buf, XLogRecord *record);
+extern const char *heap2_identify(uint8 info);
extern void heap_xlog_logical_rewrite(XLogRecPtr lsn, XLogRecord *r);
extern XLogRecPtr log_heap_cleanup_info(RelFileNode rnode,
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index f6d2e04..1910e7a 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -136,6 +136,7 @@ extern void multixact_twophase_postabort(TransactionId xid, uint16 info,
extern void multixact_redo(XLogRecPtr lsn, XLogRecord *record);
extern void multixact_desc(StringInfo buf, XLogRecord *record);
+extern const char *multixact_identify(uint8 info);
extern char *mxid_to_string(MultiXactId multi, int nmembers,
MultiXactMember *members);
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
index 9fa943f..90fd6d0 100644
--- a/src/include/access/nbtree.h
+++ b/src/include/access/nbtree.h
@@ -726,5 +726,6 @@ extern void _bt_leafbuild(BTSpool *btspool, BTSpool *spool2);
*/
extern void btree_redo(XLogRecPtr lsn, XLogRecord *record);
extern void btree_desc(StringInfo buf, XLogRecord *record);
+extern const char *btree_identify(uint8 info);
#endif /* NBTREE_H */
diff --git a/src/include/access/spgist.h b/src/include/access/spgist.h
index 7f8655c..f218a83 100644
--- a/src/include/access/spgist.h
+++ b/src/include/access/spgist.h
@@ -198,6 +198,7 @@ extern Datum spgvacuumcleanup(PG_FUNCTION_ARGS);
/* spgxlog.c */
extern void spg_redo(XLogRecPtr lsn, XLogRecord *record);
extern void spg_desc(StringInfo buf, XLogRecord *record);
+extern const char *spg_identify(uint8 info);
extern void spg_xlog_startup(void);
extern void spg_xlog_cleanup(void);
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 10ee943..ff7c426 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -257,5 +257,6 @@ extern int xactGetCommittedChildren(TransactionId **ptr);
extern void xact_redo(XLogRecPtr lsn, XLogRecord *record);
extern void xact_desc(StringInfo buf, XLogRecord *record);
+extern const char *xact_identify(uint8 info);
#endif /* XACT_H */
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 85f9cb7..e16d43c 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -299,6 +299,7 @@ extern Buffer RestoreBackupBlock(XLogRecPtr lsn, XLogRecord *record,
extern void xlog_redo(XLogRecPtr lsn, XLogRecord *record);
extern void xlog_desc(StringInfo buf, XLogRecord *record);
+extern const char *xlog_identify(uint8 info);
extern void issue_xlog_fsync(int fd, XLogSegNo segno);
diff --git a/src/include/catalog/storage_xlog.h b/src/include/catalog/storage_xlog.h
index 7081c99..5fc7235 100644
--- a/src/include/catalog/storage_xlog.h
+++ b/src/include/catalog/storage_xlog.h
@@ -45,5 +45,6 @@ extern void log_smgrcreate(RelFileNode *rnode, ForkNumber forkNum);
extern void smgr_redo(XLogRecPtr lsn, XLogRecord *record);
extern void smgr_desc(StringInfo buf, XLogRecord *record);
+extern const char *smgr_identify(uint8 info);
#endif /* STORAGE_XLOG_H */
diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h
index c2380dc..811713f 100644
--- a/src/include/commands/dbcommands.h
+++ b/src/include/commands/dbcommands.h
@@ -64,6 +64,7 @@ extern char *get_database_name(Oid dbid);
extern void dbase_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void dbase_desc(StringInfo buf, XLogRecord *rptr);
+extern const char *dbase_identify(uint8 info);
extern void check_encoding_locale_matches(int encoding, const char *collate, const char *ctype);
diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h
index 8819c00..914d155 100644
--- a/src/include/commands/sequence.h
+++ b/src/include/commands/sequence.h
@@ -78,5 +78,6 @@ extern void ResetSequenceCaches(void);
extern void seq_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void seq_desc(StringInfo buf, XLogRecord *rptr);
+extern const char *seq_identify(uint8 info);
#endif /* SEQUENCE_H */
diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h
index 073cb0d..5823bd9 100644
--- a/src/include/commands/tablespace.h
+++ b/src/include/commands/tablespace.h
@@ -58,5 +58,6 @@ extern bool directory_is_empty(const char *path);
extern void tblspc_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void tblspc_desc(StringInfo buf, XLogRecord *rptr);
+extern const char *tblspc_identify(uint8 info);
#endif /* TABLESPACE_H */
diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h
index da22fd3..1c63af5 100644
--- a/src/include/storage/standby.h
+++ b/src/include/storage/standby.h
@@ -83,6 +83,7 @@ typedef struct xl_running_xacts
/* Recovery handlers for the Standby Rmgr (RM_STANDBY_ID) */
extern void standby_redo(XLogRecPtr lsn, XLogRecord *record);
extern void standby_desc(StringInfo buf, XLogRecord *record);
+extern const char *standby_identify(uint8 info);
/*
* Declarations for GetRunningTransactionData(). Similar to Snapshots, but
diff --git a/src/include/utils/relmapper.h b/src/include/utils/relmapper.h
index 76bcf18..37937dd 100644
--- a/src/include/utils/relmapper.h
+++ b/src/include/utils/relmapper.h
@@ -60,5 +60,6 @@ extern void RelationMapInitializePhase3(void);
extern void relmap_redo(XLogRecPtr lsn, XLogRecord *record);
extern void relmap_desc(StringInfo buf, XLogRecord *record);
+extern const char *relmap_identify(uint8 info);
#endif /* RELMAPPER_H */
0004-xlogdump.difftext/x-diff; charset=us-asciiDownload
diff --git a/doc/src/sgml/pg_xlogdump.sgml b/doc/src/sgml/pg_xlogdump.sgml
index 1d1a2ce..bfd9eb9 100644
--- a/doc/src/sgml/pg_xlogdump.sgml
+++ b/doc/src/sgml/pg_xlogdump.sgml
@@ -180,6 +180,28 @@ PostgreSQL documentation
</varlistentry>
<varlistentry>
+ <term><option>-z</option></term>
+ <term><option>--stats</option></term>
+ <listitem>
+ <para>
+ Display summary statistics (number and size of records and
+ full-page images per rmgr) instead of individual records.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-Z</option></term>
+ <term><option>--record-stats</option></term>
+ <listitem>
+ <para>
+ Display summary statistics (number and size of records and
+ full-page images) instead of individual records.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-?</></term>
<term><option>--help</></term>
<listitem>
diff --git a/contrib/pg_xlogdump/pg_xlogdump.c b/contrib/pg_xlogdump/pg_xlogdump.c
index c555786..3daf023 100644
--- a/contrib/pg_xlogdump/pg_xlogdump.c
+++ b/contrib/pg_xlogdump/pg_xlogdump.c
@@ -15,9 +15,10 @@
#include <dirent.h>
#include <unistd.h>
-#include "access/xlog.h"
#include "access/xlogreader.h"
#include "access/transam.h"
+#include "catalog/pg_control.h"
+#include "catalog/storage_xlog.h"
#include "common/fe_memutils.h"
#include "getopt_long.h"
#include "rmgrdesc.h"
@@ -41,6 +42,8 @@ typedef struct XLogDumpConfig
int stop_after_records;
int already_displayed_records;
bool follow;
+ bool stats;
+ bool stats_per_record;
/* filter options */
int filter_by_rmgr;
@@ -48,6 +51,20 @@ typedef struct XLogDumpConfig
bool filter_by_xid_enabled;
} XLogDumpConfig;
+typedef struct Stats
+{
+ uint64 count;
+ uint64 rec_len;
+ uint64 fpi_len;
+} Stats;
+
+typedef struct XLogDumpStats
+{
+ uint64 count;
+ Stats rmgr_stats[RM_NEXT_ID];
+ Stats record_stats[RM_NEXT_ID][16];
+} XLogDumpStats;
+
static void
fatal_error(const char *fmt,...)
__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
@@ -322,6 +339,50 @@ XLogDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen,
}
/*
+ * Store per-rmgr and per-record statistics for a given record.
+ */
+static void
+XLogDumpCountRecord(XLogDumpConfig *config, XLogDumpStats *stats, XLogRecPtr ReadRecPtr, XLogRecord *record)
+{
+ RmgrId rmid;
+ uint8 recid;
+
+ if (config->filter_by_rmgr != -1 &&
+ config->filter_by_rmgr != record->xl_rmid)
+ return;
+
+ if (config->filter_by_xid_enabled &&
+ config->filter_by_xid != record->xl_xid)
+ return;
+
+ stats->count++;
+
+ /* Update per-rmgr statistics */
+
+ rmid = record->xl_rmid;
+
+ stats->rmgr_stats[rmid].count++;
+ stats->rmgr_stats[rmid].rec_len +=
+ record->xl_len + SizeOfXLogRecord;
+ stats->rmgr_stats[rmid].fpi_len +=
+ record->xl_tot_len - (record->xl_len + SizeOfXLogRecord);
+
+ /*
+ * Update per-record statistics, where the record is identified by a
+ * combination of the RmgrId and the upper four bits of the xl_info
+ * field (to give sixteen possible entries per RmgrId).
+ */
+
+ recid = (record->xl_info & ~XLR_INFO_MASK) >> 4;
+
+ stats->record_stats[rmid][recid].count++;
+ stats->record_stats[rmid][recid].rec_len +=
+ record->xl_len + SizeOfXLogRecord;
+ stats->record_stats[rmid][recid].fpi_len +=
+ record->xl_tot_len - (record->xl_len + SizeOfXLogRecord);
+}
+
+/*
* Print a record to stdout
*/
static void
@@ -380,6 +441,132 @@ XLogDumpDisplayRecord(XLogDumpConfig *config, XLogRecPtr ReadRecPtr, XLogRecord
}
}
+/*
+ * Display a single row of record counts and sizes for an rmgr or record.
+ */
+static void
+XLogDumpStatsRow(const char *name,
+ uint64 n, double n_pct,
+ uint64 rec_len, double rec_len_pct,
+ uint64 fpi_len, double fpi_len_pct,
+ uint64 total_len, double total_len_pct)
+{
+ printf("%-27s "
+ "%20" INT64_MODIFIER "u (%6.02f) "
+ "%20" INT64_MODIFIER "u (%6.02f) "
+ "%20" INT64_MODIFIER "u (%6.02f) "
+ "%20" INT64_MODIFIER "u (%6.02f)\n",
+ name, n, n_pct, rec_len, rec_len_pct, fpi_len, fpi_len_pct,
+ total_len, total_len_pct);
+}
+
+
+/*
+ * Display summary statistics about the records seen so far.
+ */
+static void
+XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats)
+{
+ int ri, rj;
+ uint64 total_count = 0;
+ uint64 total_rec_len = 0;
+ uint64 total_fpi_len = 0;
+ uint64 total_len = 0;
+
+ /*
+ * Make a first pass to calculate column totals:
+ * count(*),
+ * sum(xl_len+SizeOfXLogRecord),
+ * sum(xl_tot_len-xl_len-SizeOfXLogRecord), and
+ * sum(xl_tot_len).
+ * These are used to calculate percentages for each record type.
+ */
+
+ for (ri = 0; ri < RM_NEXT_ID; ri++)
+ {
+ total_count += stats->rmgr_stats[ri].count;
+ total_rec_len += stats->rmgr_stats[ri].rec_len;
+ total_fpi_len += stats->rmgr_stats[ri].fpi_len;
+ }
+ total_len = total_rec_len+total_fpi_len;
+
+ /*
+ * 27 is strlen("Transaction/COMMIT_PREPARED"),
+ * 20 is strlen(2^64), 8 is strlen("(100.00%)")
+ */
+
+ printf("%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n"
+ "%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n",
+ "Type", "N", "(%)", "Record size", "(%)", "FPI size", "(%)", "Combined size", "(%)",
+ "----", "-", "---", "-----------", "---", "--------", "---", "-------------", "---");
+
+ for (ri = 0; ri < RM_NEXT_ID; ri++)
+ {
+ uint64 count, rec_len, fpi_len, tot_len;
+ const RmgrDescData *desc = &RmgrDescTable[ri];
+
+ if (!config->stats_per_record)
+ {
+ count = stats->rmgr_stats[ri].count;
+ rec_len = stats->rmgr_stats[ri].rec_len;
+ fpi_len = stats->rmgr_stats[ri].fpi_len;
+ tot_len = rec_len + fpi_len;
+
+ XLogDumpStatsRow(desc->rm_name,
+ count, 100 * (double)count / total_count,
+ rec_len, 100 * (double)rec_len / total_rec_len,
+ fpi_len, 100 * (double)fpi_len / total_fpi_len,
+ tot_len, 100 * (double)tot_len / total_len);
+ }
+ else
+ {
+ for (rj = 0; rj < 16; rj++)
+ {
+ const char *id;
+
+ count = stats->record_stats[ri][rj].count;
+ rec_len = stats->record_stats[ri][rj].rec_len;
+ fpi_len = stats->record_stats[ri][rj].fpi_len;
+ tot_len = rec_len + fpi_len;
+
+ /* Skip undefined combinations and ones that didn't occur */
+ if (count == 0)
+ continue;
+
+ id = desc->rm_identify(rj << 4);
+ if (id == NULL)
+ id = psprintf("0x%x", rj << 4);
+
+ XLogDumpStatsRow(psprintf("%s/%s", desc->rm_name, id),
+ count, 100 * (double)count / total_count,
+ rec_len, 100 * (double)rec_len / total_rec_len,
+ fpi_len, 100 * (double)fpi_len / total_fpi_len,
+ tot_len, 100 * (double)tot_len / total_len);
+ }
+ }
+ }
+
+ printf("%-27s %20s %8s %20s %8s %20s %8s %20s\n",
+ "", "--------", "", "--------", "", "--------", "", "--------");
+
+ /*
+ * The percentages in earlier rows were calculated against the
+ * column total, but the ones that follow are against the row total.
+ * Note that these are displayed with a % symbol to differentiate
+ * them from the earlier ones, and are thus up to 9 characters long.
+ */
+
+ printf("%-27s "
+ "%20" INT64_MODIFIER "u %-9s"
+ "%20" INT64_MODIFIER "u %-9s"
+ "%20" INT64_MODIFIER "u %-9s"
+ "%20" INT64_MODIFIER "u %-6s\n",
+ "Total", stats->count, "",
+ total_rec_len, psprintf("[%.02f%%]", 100 * (double)total_rec_len / total_len),
+ total_fpi_len, psprintf("[%.02f%%]", 100 * (double)total_fpi_len / total_len),
+ total_len, "[100%]");
+}
+
static void
usage(void)
{
@@ -401,6 +588,8 @@ usage(void)
printf(" (default: 1 or the value used in STARTSEG)\n");
printf(" -V, --version output version information, then exit\n");
printf(" -x, --xid=XID only show records with TransactionId XID\n");
+ printf(" -z, --stats show per-rmgr statistics\n");
+ printf(" -Z, --record-stats show per-record statistics\n");
printf(" -?, --help show this help, then exit\n");
}
@@ -412,6 +601,7 @@ main(int argc, char **argv)
XLogReaderState *xlogreader_state;
XLogDumpPrivate private;
XLogDumpConfig config;
+ XLogDumpStats stats;
XLogRecord *record;
XLogRecPtr first_record;
char *errormsg;
@@ -428,6 +618,8 @@ main(int argc, char **argv)
{"timeline", required_argument, NULL, 't'},
{"xid", required_argument, NULL, 'x'},
{"version", no_argument, NULL, 'V'},
+ {"stats", no_argument, NULL, 'z'},
+ {"record-stats", no_argument, NULL, 'Z'},
{NULL, 0, NULL, 0}
};
@@ -438,6 +630,7 @@ main(int argc, char **argv)
memset(&private, 0, sizeof(XLogDumpPrivate));
memset(&config, 0, sizeof(XLogDumpConfig));
+ memset(&stats, 0, sizeof(XLogDumpStats));
private.timeline = 1;
private.startptr = InvalidXLogRecPtr;
@@ -451,6 +644,8 @@ main(int argc, char **argv)
config.filter_by_rmgr = -1;
config.filter_by_xid = InvalidTransactionId;
config.filter_by_xid_enabled = false;
+ config.stats = false;
+ config.stats_per_record = false;
if (argc <= 1)
{
@@ -458,7 +653,7 @@ main(int argc, char **argv)
goto bad_argument;
}
- while ((option = getopt_long(argc, argv, "be:?fn:p:r:s:t:Vx:",
+ while ((option = getopt_long(argc, argv, "be:?fn:p:r:s:t:Vx:zZ",
long_options, &optindex)) != -1)
{
switch (option)
@@ -551,6 +746,13 @@ main(int argc, char **argv)
}
config.filter_by_xid_enabled = true;
break;
+ case 'z':
+ config.stats = true;
+ break;
+ case 'Z':
+ config.stats = true;
+ config.stats_per_record = true;
+ break;
default:
goto bad_argument;
}
@@ -711,7 +913,10 @@ main(int argc, char **argv)
/* after reading the first record, continue at next one */
first_record = InvalidXLogRecPtr;
- XLogDumpDisplayRecord(&config, xlogreader_state->ReadRecPtr, record);
+ if (config.stats == true)
+ XLogDumpCountRecord(&config, &stats, xlogreader_state->ReadRecPtr, record);
+ else
+ XLogDumpDisplayRecord(&config, xlogreader_state->ReadRecPtr, record);
/* check whether we printed enough */
if (config.stop_after_records > 0 &&
@@ -719,6 +924,9 @@ main(int argc, char **argv)
break;
}
+ if (config.stats == true)
+ XLogDumpDisplayStats(&config, &stats);
+
if (errormsg)
fatal_error("error in WAL record at %X/%X: %s\n",
(uint32) (xlogreader_state->ReadRecPtr >> 32),
Andres Freund wrote:
On 2014-07-04 18:31:34 +0800, gotoschool6g wrote:
Carp the code:
const char *
clog_identify(uint8 info)
{
switch (info)
{
case CLOG_ZEROPAGE:
return "ZEROPAGE";
case CLOG_TRUNCATE:
return "TRUNCATE";
break;
}
return NULL;
}
I agree that performance is secondary here. The part that I don't quite
like in all these blocks is the fact that they initialize the return
value to NULL beforehand, and there's no 'default' label. Now, I see
that pg_xlogdump is checking for NULL return, but I'm not sure this is
the best possible API. Shouldn't we perhaps return a different string
that indicates there is no known description?
Also, are we certain that we're never going to need anything other than
the "info" to identify the record? In practice we seem to follow that
rule currently, but it's not totally out of the question that someday
the rm_redo function uses more than just "info" to identify the record.
I wonder if it'd be better to pass the whole record instead and have the
rm_identify function pull out the info if it's all it needs, but leave
the possibility open that it could read, say, some header bytes in the
record data.
Also I didn't check how you handle the "init" bit in RM_HEAP and
RM_HEAP2. Are we just saying that "insert (init)" is a different record
type from "insert"? Maybe that's okay, but I'm not 100% sure.
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
At 2014-07-04 13:43:46 -0400, alvherre@2ndquadrant.com wrote:
Now, I see that pg_xlogdump is checking for NULL return, but I'm not
sure this is the best possible API.
Note that the patched pg_xlogdump will display "rm_name/0xNN" for any
records that rm_identify returns a NULL for.
Earlier, when there was the possibility that new record types could be
added without updating pg_xlogdump's identification code, this made good
sense. Now one could argue that pg_xlogdump should fully depend on every
record in WAL being properly identified.
If that's the case, rm_identify could return "UNKNOWN", and pg_xlogdump
could use the return value without checking. I considered that, but the
only thing that stopped me was the thought that if a "weird" record DOES
show up in WAL somehow, it'd be pretty handy to (a) know the value of
xl_info, and (b) see if there's more than one kind (per-rmid).
But I don't feel strongly enough about it that I'd object to displaying
just "UNKNOWN".
I wonder if it'd be better to pass the whole record instead and have
the rm_identify function pull out the info if it's all it needs, but
leave the possibility open that it could read, say, some header bytes
in the record data.
I don't *have* an XLogRecord at the point where I'm calling rm_identify.
I could call rm_identify earlier, and either store the name in the stats
structure, or hash the name and use the hash value to store that record
type's statistics.
We don't even have any other potential callers for rm_identify. Adding
it and making it significantly more difficult to use for the only code
that actually needs it… no, I pretty much hate that idea.
Personally, I think it's fine to keep rm_identify the way it is. It's
hardly very difficult code, and if the assumption that records can be
identified by xl_info ever becomes invalid, this isn't the only code
that will need to be changed either.
(Otherwise, I'd actually prefer to keep all the identification code in
pg_xlogdump, i.e. the pre-rm_identify version of my patch. At least that
would make it possible to maintain a version that could be built against
9.3, the way Marti did.)
Also I didn't check how you handle the "init" bit in RM_HEAP and
RM_HEAP2. Are we just saying that "insert (init)" is a different
record type from "insert"?
Yes, that's what the patch does currently. "X" vs. "X+INIT".
-- Abhijit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2014-07-04 18:59:07 +0530, Abhijit Menon-Sen wrote:
At 2014-07-04 11:34:21 +0200, andres@2ndquadrant.com wrote:
I think we're going to have to redefine the
PGAC_FUNC_SNPRINTF_LONG_LONG_INT_FORMAT callsite in configure.in to
define INT64_MODIFIER='"ll/l/I64D"'I've attached a patch to do this, and also add INT64_MODIFIER to
pg_config.h.in: 0001-modifier.diffI reran autoconf, and just for convenience I've attached the resulting
changes to configure: 0002-configure.diffThen there are the rm_identify changes: 0003-rmid.diff
Finally, the xlogdump patch using INT64_MODIFIER: 0004-xlogdump.diff
I can confirm that this series applies in-order to master, and that the
result builds cleanly (including after each patch) on my machine, and
that the resulting pg_xlogdump works as expected.
Two of the extra calls to psprintf in pg_xlogdump happen at most
RM_MAX_ID*16 (i.e. O(record-types) not O(records)) times, and the other
two happen just before exit. It would be easy to use a static buffer and
snprintf, but I don't think it's worth doing in this case.
Agreed.
diff --git a/config/c-library.m4 b/config/c-library.m4 index 8f45010..4821a61 100644 --- a/config/c-library.m4 +++ b/config/c-library.m4 @@ -221,22 +221,22 @@ HAVE_POSIX_SIGNALS=$pgac_cv_func_posix_signals AC_SUBST(HAVE_POSIX_SIGNALS)])# PGAC_FUNC_POSIX_SIGNALS-# PGAC_FUNC_SNPRINTF_LONG_LONG_INT_FORMAT +# PGAC_FUNC_SNPRINTF_LONG_LONG_INT_MODIFIER # --------------------------------------- -# Determine which format snprintf uses for long long int. We handle -# %lld, %qd, %I64d. The result is in shell variable -# LONG_LONG_INT_FORMAT. +# Determine which length modifier snprintf uses for long long int. We +# handle ll, q, and I64. The result is in shell variable +# LONG_LONG_INT_MODIFIER. # # MinGW uses '%I64d', though gcc throws an warning with -Wall, # while '%lld' doesn't generate a warning, but doesn't work. # -AC_DEFUN([PGAC_FUNC_SNPRINTF_LONG_LONG_INT_FORMAT], -[AC_MSG_CHECKING([snprintf format for long long int]) -AC_CACHE_VAL(pgac_cv_snprintf_long_long_int_format, -[for pgac_format in '%lld' '%qd' '%I64d'; do +AC_DEFUN([PGAC_FUNC_SNPRINTF_LONG_LONG_INT_MODIFIER], +[AC_MSG_CHECKING([snprintf length modifier for long long int]) +AC_CACHE_VAL(pgac_cv_snprintf_long_long_int_modifier, +[for pgac_modifier in 'll' 'q' 'I64'; do AC_TRY_RUN([#include <stdio.h> typedef long long int ac_int64; -#define INT64_FORMAT "$pgac_format" +#define INT64_FORMAT "%${pgac_modifier}d"
I'd rather not define INT64_FORMAT here.
+INT64_FORMAT="\"%${LONG_LONG_INT_MODIFIER}d\"" +UINT64_FORMAT="\"%${LONG_LONG_INT_MODIFIER}u\"" +INT64_MODIFIER="\"$LONG_LONG_INT_MODIFIER\"" +
AC_DEFINE_UNQUOTED(INT64_FORMAT, $INT64_FORMAT,
[Define to the appropriate snprintf format for 64-bit ints.])AC_DEFINE_UNQUOTED(UINT64_FORMAT, $UINT64_FORMAT,
[Define to the appropriate snprintf format for unsigned 64-bit ints.])+AC_DEFINE_UNQUOTED(INT64_MODIFIER, $INT64_MODIFIER, + [Define to the appropriate snprintf length modifier for 64-bit ints.]) +
I'd suggest only defining INT64_MODIFIER here and build INT64_FORMAT,
UINT64_FORMAT ontop, in c.h.
NOTE: I do not know what to do about pg_config.h.win32. If someone tells
me what to do, I can submit another patch.
Which would also take care of pg_config.h.win32 - just define
INT64_MODIFIER in there instead of INT64_FORMAT/UINT64_FORMAT and you
should be good.
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
At 2014-07-07 09:48:44 +0200, andres@2ndquadrant.com wrote:
I'd suggest only defining INT64_MODIFIER here and build INT64_FORMAT,
UINT64_FORMAT ontop, in c.h.
Oh, I see. I'm sorry, I misread your earlier suggestion. Regenerated
patches attached. Is this what you had in mind?
-- Abhijit
Attachments:
0001-modifier.difftext/x-diff; charset=us-asciiDownload
diff --git a/src/include/c.h b/src/include/c.h
index a48a57a..999f297 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -864,6 +864,9 @@ typedef NameData *Name;
* ----------------------------------------------------------------
*/
+#define INT64_FORMAT "%" INT64_MODIFIER "d"
+#define UINT64_FORMAT "%" INT64_MODIFIER "u"
+
/* msb for char */
#define HIGHBIT (0x80)
#define IS_HIGHBIT_SET(ch) ((unsigned char)(ch) & HIGHBIT)
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 2a40d61..c2e01fd 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -650,8 +650,8 @@
/* Define to 1 if your compiler understands __VA_ARGS__ in macros. */
#undef HAVE__VA_ARGS
-/* Define to the appropriate snprintf format for 64-bit ints. */
-#undef INT64_FORMAT
+/* Define to the appropriate snprintf length modifier for 64-bit ints. */
+#undef INT64_MODIFIER
/* Define to 1 if `locale_t' requires <xlocale.h>. */
#undef LOCALE_T_IN_XLOCALE
@@ -741,9 +741,6 @@
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
#undef TM_IN_SYS_TIME
-/* Define to the appropriate snprintf format for unsigned 64-bit ints. */
-#undef UINT64_FORMAT
-
/* Define to 1 to build with assertion checks. (--enable-cassert) */
#undef USE_ASSERT_CHECKING
diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32
index 1c9cd82..a238a72 100644
--- a/src/include/pg_config.h.win32
+++ b/src/include/pg_config.h.win32
@@ -529,8 +529,8 @@
/* Define to 1 if your compiler understands __VA_ARGS__ in macros. */
#define HAVE__VA_ARGS 1
-/* Define to the appropriate snprintf format for 64-bit ints, if any. */
-#define INT64_FORMAT "%lld"
+/* Define to the appropriate snprintf length modifier for 64-bit ints. */
+#undef INT64_MODIFIER
/* Define to 1 if `locale_t' requires <xlocale.h>. */
/* #undef LOCALE_T_IN_XLOCALE */
@@ -601,10 +601,6 @@
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
/* #undef TM_IN_SYS_TIME */
-/* Define to the appropriate snprintf format for unsigned 64-bit ints, if any.
- */
-#define UINT64_FORMAT "%llu"
-
/* Define to 1 to build with assertion checks. (--enable-cassert) */
/* #undef USE_ASSERT_CHECKING */
diff --git a/configure.in b/configure.in
index c938a5d..7750c30 100644
--- a/configure.in
+++ b/configure.in
@@ -1636,34 +1636,29 @@ fi
# If we found "long int" is 64 bits, assume snprintf handles it. If
# we found we need to use "long long int", better check. We cope with
# snprintfs that use %lld, %qd, or %I64d as the format. If none of these
-# work, fall back to our own snprintf emulation (which we know uses %lld).
+# works, fall back to our own snprintf emulation (which we know uses %lld).
if test "$HAVE_LONG_LONG_INT_64" = yes ; then
if test $pgac_need_repl_snprintf = no; then
- PGAC_FUNC_SNPRINTF_LONG_LONG_INT_FORMAT
- if test "$LONG_LONG_INT_FORMAT" = ""; then
+ PGAC_FUNC_SNPRINTF_LONG_LONG_INT_MODIFIER
+ if test "$LONG_LONG_INT_MODIFIER" = ""; then
# Force usage of our own snprintf, since system snprintf is broken
pgac_need_repl_snprintf=yes
- LONG_LONG_INT_FORMAT='%lld'
+ LONG_LONG_INT_MODIFIER='ll'
fi
else
# Here if we previously decided we needed to use our own snprintf
- LONG_LONG_INT_FORMAT='%lld'
+ LONG_LONG_INT_MODIFIER='ll'
fi
- LONG_LONG_UINT_FORMAT=`echo "$LONG_LONG_INT_FORMAT" | sed 's/d$/u/'`
- INT64_FORMAT="\"$LONG_LONG_INT_FORMAT\""
- UINT64_FORMAT="\"$LONG_LONG_UINT_FORMAT\""
else
# Here if we are not using 'long long int' at all
- INT64_FORMAT='"%ld"'
- UINT64_FORMAT='"%lu"'
+ LONG_LONG_INT_MODIFIER='l'
fi
-AC_DEFINE_UNQUOTED(INT64_FORMAT, $INT64_FORMAT,
- [Define to the appropriate snprintf format for 64-bit ints.])
+INT64_MODIFIER="\"$LONG_LONG_INT_MODIFIER\""
-AC_DEFINE_UNQUOTED(UINT64_FORMAT, $UINT64_FORMAT,
- [Define to the appropriate snprintf format for unsigned 64-bit ints.])
+AC_DEFINE_UNQUOTED(INT64_MODIFIER, $INT64_MODIFIER,
+ [Define to the appropriate snprintf length modifier for 64-bit ints.])
# Also force use of our snprintf if the system's doesn't support the %z flag.
if test "$pgac_need_repl_snprintf" = no; then
diff --git a/config/c-library.m4 b/config/c-library.m4
index 8f45010..4821a61 100644
--- a/config/c-library.m4
+++ b/config/c-library.m4
@@ -221,22 +221,22 @@ HAVE_POSIX_SIGNALS=$pgac_cv_func_posix_signals
AC_SUBST(HAVE_POSIX_SIGNALS)])# PGAC_FUNC_POSIX_SIGNALS
-# PGAC_FUNC_SNPRINTF_LONG_LONG_INT_FORMAT
+# PGAC_FUNC_SNPRINTF_LONG_LONG_INT_MODIFIER
# ---------------------------------------
-# Determine which format snprintf uses for long long int. We handle
-# %lld, %qd, %I64d. The result is in shell variable
-# LONG_LONG_INT_FORMAT.
+# Determine which length modifier snprintf uses for long long int. We
+# handle ll, q, and I64. The result is in shell variable
+# LONG_LONG_INT_MODIFIER.
#
# MinGW uses '%I64d', though gcc throws an warning with -Wall,
# while '%lld' doesn't generate a warning, but doesn't work.
#
-AC_DEFUN([PGAC_FUNC_SNPRINTF_LONG_LONG_INT_FORMAT],
-[AC_MSG_CHECKING([snprintf format for long long int])
-AC_CACHE_VAL(pgac_cv_snprintf_long_long_int_format,
-[for pgac_format in '%lld' '%qd' '%I64d'; do
+AC_DEFUN([PGAC_FUNC_SNPRINTF_LONG_LONG_INT_MODIFIER],
+[AC_MSG_CHECKING([snprintf length modifier for long long int])
+AC_CACHE_VAL(pgac_cv_snprintf_long_long_int_modifier,
+[for pgac_modifier in 'll' 'q' 'I64'; do
AC_TRY_RUN([#include <stdio.h>
typedef long long int ac_int64;
-#define INT64_FORMAT "$pgac_format"
+#define INT64_FORMAT "%${pgac_modifier}d"
ac_int64 a = 20000001;
ac_int64 b = 40000005;
@@ -258,19 +258,19 @@ int does_int64_snprintf_work()
main() {
exit(! does_int64_snprintf_work());
}],
-[pgac_cv_snprintf_long_long_int_format=$pgac_format; break],
+[pgac_cv_snprintf_long_long_int_modifier=$pgac_modifier; break],
[],
-[pgac_cv_snprintf_long_long_int_format=cross; break])
+[pgac_cv_snprintf_long_long_int_modifier=cross; break])
done])dnl AC_CACHE_VAL
-LONG_LONG_INT_FORMAT=''
+LONG_LONG_INT_MODIFIER=''
-case $pgac_cv_snprintf_long_long_int_format in
+case $pgac_cv_snprintf_long_long_int_modifier in
cross) AC_MSG_RESULT([cannot test (not on host machine)]);;
- ?*) AC_MSG_RESULT([$pgac_cv_snprintf_long_long_int_format])
- LONG_LONG_INT_FORMAT=$pgac_cv_snprintf_long_long_int_format;;
+ ?*) AC_MSG_RESULT([$pgac_cv_snprintf_long_long_int_modifier])
+ LONG_LONG_INT_MODIFIER=$pgac_cv_snprintf_long_long_int_modifier;;
*) AC_MSG_RESULT(none);;
-esac])# PGAC_FUNC_SNPRINTF_LONG_LONG_INT_FORMAT
+esac])# PGAC_FUNC_SNPRINTF_LONG_LONG_INT_MODIFIER
# PGAC_FUNC_SNPRINTF_ARG_CONTROL
0002-configure.difftext/x-diff; charset=us-asciiDownload
diff --git a/configure b/configure
index 481096c..46f828b 100755
--- a/configure
+++ b/configure
@@ -13039,24 +13039,24 @@ fi
# If we found "long int" is 64 bits, assume snprintf handles it. If
# we found we need to use "long long int", better check. We cope with
# snprintfs that use %lld, %qd, or %I64d as the format. If none of these
-# work, fall back to our own snprintf emulation (which we know uses %lld).
+# works, fall back to our own snprintf emulation (which we know uses %lld).
if test "$HAVE_LONG_LONG_INT_64" = yes ; then
if test $pgac_need_repl_snprintf = no; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking snprintf format for long long int" >&5
-$as_echo_n "checking snprintf format for long long int... " >&6; }
-if ${pgac_cv_snprintf_long_long_int_format+:} false; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking snprintf length modifier for long long int" >&5
+$as_echo_n "checking snprintf length modifier for long long int... " >&6; }
+if ${pgac_cv_snprintf_long_long_int_modifier+:} false; then :
$as_echo_n "(cached) " >&6
else
- for pgac_format in '%lld' '%qd' '%I64d'; do
+ for pgac_modifier in 'll' 'q' 'I64'; do
if test "$cross_compiling" = yes; then :
- pgac_cv_snprintf_long_long_int_format=cross; break
+ pgac_cv_snprintf_long_long_int_modifier=cross; break
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
typedef long long int ac_int64;
-#define INT64_FORMAT "$pgac_format"
+#define INT64_FORMAT "%${pgac_modifier}d"
ac_int64 a = 20000001;
ac_int64 b = 40000005;
@@ -13080,7 +13080,7 @@ main() {
}
_ACEOF
if ac_fn_c_try_run "$LINENO"; then :
- pgac_cv_snprintf_long_long_int_format=$pgac_format; break
+ pgac_cv_snprintf_long_long_int_modifier=$pgac_modifier; break
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
@@ -13089,44 +13089,36 @@ fi
done
fi
-LONG_LONG_INT_FORMAT=''
+LONG_LONG_INT_MODIFIER=''
-case $pgac_cv_snprintf_long_long_int_format in
+case $pgac_cv_snprintf_long_long_int_modifier in
cross) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cannot test (not on host machine)" >&5
$as_echo "cannot test (not on host machine)" >&6; };;
- ?*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_snprintf_long_long_int_format" >&5
-$as_echo "$pgac_cv_snprintf_long_long_int_format" >&6; }
- LONG_LONG_INT_FORMAT=$pgac_cv_snprintf_long_long_int_format;;
+ ?*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_snprintf_long_long_int_modifier" >&5
+$as_echo "$pgac_cv_snprintf_long_long_int_modifier" >&6; }
+ LONG_LONG_INT_MODIFIER=$pgac_cv_snprintf_long_long_int_modifier;;
*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
$as_echo "none" >&6; };;
esac
- if test "$LONG_LONG_INT_FORMAT" = ""; then
+ if test "$LONG_LONG_INT_MODIFIER" = ""; then
# Force usage of our own snprintf, since system snprintf is broken
pgac_need_repl_snprintf=yes
- LONG_LONG_INT_FORMAT='%lld'
+ LONG_LONG_INT_MODIFIER='ll'
fi
else
# Here if we previously decided we needed to use our own snprintf
- LONG_LONG_INT_FORMAT='%lld'
+ LONG_LONG_INT_MODIFIER='ll'
fi
- LONG_LONG_UINT_FORMAT=`echo "$LONG_LONG_INT_FORMAT" | sed 's/d$/u/'`
- INT64_FORMAT="\"$LONG_LONG_INT_FORMAT\""
- UINT64_FORMAT="\"$LONG_LONG_UINT_FORMAT\""
else
# Here if we are not using 'long long int' at all
- INT64_FORMAT='"%ld"'
- UINT64_FORMAT='"%lu"'
+ LONG_LONG_INT_MODIFIER='l'
fi
-
-cat >>confdefs.h <<_ACEOF
-#define INT64_FORMAT $INT64_FORMAT
-_ACEOF
-
+INT64_MODIFIER="\"$LONG_LONG_INT_MODIFIER\""
cat >>confdefs.h <<_ACEOF
-#define UINT64_FORMAT $UINT64_FORMAT
+#define INT64_MODIFIER $INT64_MODIFIER
_ACEOF
0003-rmid.difftext/x-diff; charset=us-asciiDownload
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index 8c8de38..5839426 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -246,6 +246,7 @@ typedef struct RmgrData
const char *rm_name;
void (*rm_redo) (XLogRecPtr lsn, struct XLogRecord *rptr);
void (*rm_desc) (StringInfo buf, struct XLogRecord *rptr);
+ const char *(*rm_identify) (uint8 info);
void (*rm_startup) (void);
void (*rm_cleanup) (void);
} RmgrData;
diff --git a/src/include/access/rmgr.h b/src/include/access/rmgr.h
index 1b577a2..ff7fe62 100644
--- a/src/include/access/rmgr.h
+++ b/src/include/access/rmgr.h
@@ -19,7 +19,7 @@ typedef uint8 RmgrId;
* Note: RM_MAX_ID must fit in RmgrId; widening that type will affect the XLOG
* file format.
*/
-#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \
+#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \
symname,
typedef enum RmgrIds
diff --git a/src/include/access/rmgrlist.h b/src/include/access/rmgrlist.h
index 662fb77..77d4574 100644
--- a/src/include/access/rmgrlist.h
+++ b/src/include/access/rmgrlist.h
@@ -25,20 +25,20 @@
*/
/* symbol name, textual name, redo, desc, startup, cleanup */
-PG_RMGR(RM_XLOG_ID, "XLOG", xlog_redo, xlog_desc, NULL, NULL)
-PG_RMGR(RM_XACT_ID, "Transaction", xact_redo, xact_desc, NULL, NULL)
-PG_RMGR(RM_SMGR_ID, "Storage", smgr_redo, smgr_desc, NULL, NULL)
-PG_RMGR(RM_CLOG_ID, "CLOG", clog_redo, clog_desc, NULL, NULL)
-PG_RMGR(RM_DBASE_ID, "Database", dbase_redo, dbase_desc, NULL, NULL)
-PG_RMGR(RM_TBLSPC_ID, "Tablespace", tblspc_redo, tblspc_desc, NULL, NULL)
-PG_RMGR(RM_MULTIXACT_ID, "MultiXact", multixact_redo, multixact_desc, NULL, NULL)
-PG_RMGR(RM_RELMAP_ID, "RelMap", relmap_redo, relmap_desc, NULL, NULL)
-PG_RMGR(RM_STANDBY_ID, "Standby", standby_redo, standby_desc, NULL, NULL)
-PG_RMGR(RM_HEAP2_ID, "Heap2", heap2_redo, heap2_desc, NULL, NULL)
-PG_RMGR(RM_HEAP_ID, "Heap", heap_redo, heap_desc, NULL, NULL)
-PG_RMGR(RM_BTREE_ID, "Btree", btree_redo, btree_desc, NULL, NULL)
-PG_RMGR(RM_HASH_ID, "Hash", hash_redo, hash_desc, NULL, NULL)
-PG_RMGR(RM_GIN_ID, "Gin", gin_redo, gin_desc, gin_xlog_startup, gin_xlog_cleanup)
-PG_RMGR(RM_GIST_ID, "Gist", gist_redo, gist_desc, gist_xlog_startup, gist_xlog_cleanup)
-PG_RMGR(RM_SEQ_ID, "Sequence", seq_redo, seq_desc, NULL, NULL)
-PG_RMGR(RM_SPGIST_ID, "SPGist", spg_redo, spg_desc, spg_xlog_startup, spg_xlog_cleanup)
+PG_RMGR(RM_XLOG_ID, "XLOG", xlog_redo, xlog_desc, xlog_identify, NULL, NULL)
+PG_RMGR(RM_XACT_ID, "Transaction", xact_redo, xact_desc, xact_identify, NULL, NULL)
+PG_RMGR(RM_SMGR_ID, "Storage", smgr_redo, smgr_desc, smgr_identify, NULL, NULL)
+PG_RMGR(RM_CLOG_ID, "CLOG", clog_redo, clog_desc, clog_identify, NULL, NULL)
+PG_RMGR(RM_DBASE_ID, "Database", dbase_redo, dbase_desc, dbase_identify, NULL, NULL)
+PG_RMGR(RM_TBLSPC_ID, "Tablespace", tblspc_redo, tblspc_desc, tblspc_identify, NULL, NULL)
+PG_RMGR(RM_MULTIXACT_ID, "MultiXact", multixact_redo, multixact_desc, multixact_identify, NULL, NULL)
+PG_RMGR(RM_RELMAP_ID, "RelMap", relmap_redo, relmap_desc, relmap_identify, NULL, NULL)
+PG_RMGR(RM_STANDBY_ID, "Standby", standby_redo, standby_desc, standby_identify, NULL, NULL)
+PG_RMGR(RM_HEAP2_ID, "Heap2", heap2_redo, heap2_desc, heap2_identify, NULL, NULL)
+PG_RMGR(RM_HEAP_ID, "Heap", heap_redo, heap_desc, heap_identify, NULL, NULL)
+PG_RMGR(RM_BTREE_ID, "Btree", btree_redo, btree_desc, btree_identify, NULL, NULL)
+PG_RMGR(RM_HASH_ID, "Hash", hash_redo, hash_desc, hash_identify, NULL, NULL)
+PG_RMGR(RM_GIN_ID, "Gin", gin_redo, gin_desc, gin_identify, gin_xlog_startup, gin_xlog_cleanup)
+PG_RMGR(RM_GIST_ID, "Gist", gist_redo, gist_desc, gist_identify, gist_xlog_startup, gist_xlog_cleanup)
+PG_RMGR(RM_SEQ_ID, "Sequence", seq_redo, seq_desc, seq_identify, NULL, NULL)
+PG_RMGR(RM_SPGIST_ID, "SPGist", spg_redo, spg_desc, spg_identify, spg_xlog_startup, spg_xlog_cleanup)
diff --git a/contrib/pg_xlogdump/rmgrdesc.h b/contrib/pg_xlogdump/rmgrdesc.h
index d964118..da805c5 100644
--- a/contrib/pg_xlogdump/rmgrdesc.h
+++ b/contrib/pg_xlogdump/rmgrdesc.h
@@ -14,6 +14,7 @@ typedef struct RmgrDescData
{
const char *rm_name;
void (*rm_desc) (StringInfo buf, XLogRecord *record);
+ const char *(*rm_identify) (uint8 info);
} RmgrDescData;
extern const RmgrDescData RmgrDescTable[];
diff --git a/contrib/pg_xlogdump/rmgrdesc.c b/contrib/pg_xlogdump/rmgrdesc.c
index cbcaaa6..dc27fd1 100644
--- a/contrib/pg_xlogdump/rmgrdesc.c
+++ b/contrib/pg_xlogdump/rmgrdesc.c
@@ -27,8 +27,8 @@
#include "storage/standby.h"
#include "utils/relmapper.h"
-#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \
- { name, desc, },
+#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \
+ { name, desc, identify, },
const RmgrDescData RmgrDescTable[RM_MAX_ID + 1] = {
#include "access/rmgrlist.h"
diff --git a/src/backend/access/rmgrdesc/clogdesc.c b/src/backend/access/rmgrdesc/clogdesc.c
index e82baa8..08f225d 100644
--- a/src/backend/access/rmgrdesc/clogdesc.c
+++ b/src/backend/access/rmgrdesc/clogdesc.c
@@ -40,3 +40,21 @@ clog_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+clog_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case CLOG_ZEROPAGE:
+ id = "ZEROPAGE";
+ break;
+ case CLOG_TRUNCATE:
+ id = "TRUNCATE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/dbasedesc.c b/src/backend/access/rmgrdesc/dbasedesc.c
index 0230716..38f3a39 100644
--- a/src/backend/access/rmgrdesc/dbasedesc.c
+++ b/src/backend/access/rmgrdesc/dbasedesc.c
@@ -42,3 +42,21 @@ dbase_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+dbase_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_DBASE_CREATE:
+ id = "CREATE";
+ break;
+ case XLOG_DBASE_DROP:
+ id = "DROP";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/gindesc.c b/src/backend/access/rmgrdesc/gindesc.c
index 12d68d7..115ad5b 100644
--- a/src/backend/access/rmgrdesc/gindesc.c
+++ b/src/backend/access/rmgrdesc/gindesc.c
@@ -187,3 +187,45 @@ gin_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+gin_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_GIN_CREATE_INDEX:
+ id = "CREATE_INDEX";
+ break;
+ case XLOG_GIN_CREATE_PTREE:
+ id = "CREATE_PTREE";
+ break;
+ case XLOG_GIN_INSERT:
+ id = "INSERT";
+ break;
+ case XLOG_GIN_SPLIT:
+ id = "SPLIT";
+ break;
+ case XLOG_GIN_VACUUM_PAGE:
+ id = "VACUUM_PAGE";
+ break;
+ case XLOG_GIN_VACUUM_DATA_LEAF_PAGE:
+ id = "VACUUM_DATA_LEAF_PAGE";
+ break;
+ case XLOG_GIN_DELETE_PAGE:
+ id = "DELETE_PAGE";
+ break;
+ case XLOG_GIN_UPDATE_META_PAGE:
+ id = "UPDATE_META_PAGE";
+ break;
+ case XLOG_GIN_INSERT_LISTPAGE:
+ id = "INSERT_LISTPAGE";
+ break;
+ case XLOG_GIN_DELETE_LISTPAGE:
+ id = "DELETE_LISTPAGE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/gistdesc.c b/src/backend/access/rmgrdesc/gistdesc.c
index cdac496..e4f288b 100644
--- a/src/backend/access/rmgrdesc/gistdesc.c
+++ b/src/backend/access/rmgrdesc/gistdesc.c
@@ -67,3 +67,24 @@ gist_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+gist_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_GIST_PAGE_UPDATE:
+ id = "PAGE_UPDATE";
+ break;
+ case XLOG_GIST_PAGE_SPLIT:
+ id = "PAGE_SPLIT";
+ break;
+ case XLOG_GIST_CREATE_INDEX:
+ id = "CREATE_INDEX";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/hashdesc.c b/src/backend/access/rmgrdesc/hashdesc.c
index 86a0376..c58461c 100644
--- a/src/backend/access/rmgrdesc/hashdesc.c
+++ b/src/backend/access/rmgrdesc/hashdesc.c
@@ -20,3 +20,9 @@ void
hash_desc(StringInfo buf, XLogRecord *record)
{
}
+
+const char *
+hash_identify(uint8 info)
+{
+ return NULL;
+}
diff --git a/src/backend/access/rmgrdesc/heapdesc.c b/src/backend/access/rmgrdesc/heapdesc.c
index 7df18fa..74a654c 100644
--- a/src/backend/access/rmgrdesc/heapdesc.c
+++ b/src/backend/access/rmgrdesc/heapdesc.c
@@ -202,3 +202,89 @@ heap2_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+static const char *
+append_init(const char *str)
+{
+ static char x[32];
+
+ strcpy(x, str);
+ strcat(x, "+INIT");
+
+ return x;
+}
+
+const char *
+heap_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info & XLOG_HEAP_OPMASK)
+ {
+ case XLOG_HEAP_INSERT:
+ id = "INSERT";
+ break;
+ case XLOG_HEAP_DELETE:
+ id = "DELETE";
+ break;
+ case XLOG_HEAP_UPDATE:
+ id = "UPDATE";
+ break;
+ case XLOG_HEAP_HOT_UPDATE:
+ id = "HOT_UPDATE";
+ break;
+ case XLOG_HEAP_NEWPAGE:
+ id = "NEWPAGE";
+ break;
+ case XLOG_HEAP_LOCK:
+ id = "LOCK";
+ break;
+ case XLOG_HEAP_INPLACE:
+ id = "INPLACE";
+ break;
+ }
+
+ if (info & XLOG_HEAP_INIT_PAGE)
+ id = append_init(id);
+
+ return id;
+}
+
+const char *
+heap2_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info & XLOG_HEAP_OPMASK)
+ {
+ case XLOG_HEAP2_CLEAN:
+ id = "CLEAN";
+ break;
+ case XLOG_HEAP2_FREEZE_PAGE:
+ id = "FREEZE_PAGE";
+ break;
+ case XLOG_HEAP2_CLEANUP_INFO:
+ id = "CLEANUP_INFO";
+ break;
+ case XLOG_HEAP2_VISIBLE:
+ id = "VISIBLE";
+ break;
+ case XLOG_HEAP2_MULTI_INSERT:
+ id = "MULTI_INSERT";
+ break;
+ case XLOG_HEAP2_LOCK_UPDATED:
+ id = "LOCK_UPDATED";
+ break;
+ case XLOG_HEAP2_NEW_CID:
+ id = "NEW_CID";
+ break;
+ case XLOG_HEAP2_REWRITE:
+ id = "REWRITE";
+ break;
+ }
+
+ if (info & XLOG_HEAP_INIT_PAGE)
+ id = append_init(id);
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/mxactdesc.c b/src/backend/access/rmgrdesc/mxactdesc.c
index 50d9b55..d77b1c8 100644
--- a/src/backend/access/rmgrdesc/mxactdesc.c
+++ b/src/backend/access/rmgrdesc/mxactdesc.c
@@ -79,3 +79,24 @@ multixact_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+multixact_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_MULTIXACT_ZERO_OFF_PAGE:
+ id = "ZERO_OFF_PAGE";
+ break;
+ case XLOG_MULTIXACT_ZERO_MEM_PAGE:
+ id = "ZERO_MEM_PAGE";
+ break;
+ case XLOG_MULTIXACT_CREATE_ID:
+ id = "CREATE_ID";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/nbtdesc.c b/src/backend/access/rmgrdesc/nbtdesc.c
index bf3389c..821715c 100644
--- a/src/backend/access/rmgrdesc/nbtdesc.c
+++ b/src/backend/access/rmgrdesc/nbtdesc.c
@@ -172,3 +172,57 @@ btree_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+btree_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_BTREE_INSERT_LEAF:
+ id = "INSERT_LEAF";
+ break;
+ case XLOG_BTREE_INSERT_UPPER:
+ id = "INSERT_UPPER";
+ break;
+ case XLOG_BTREE_INSERT_META:
+ id = "INSERT_META";
+ break;
+ case XLOG_BTREE_SPLIT_L:
+ id = "SPLIT_L";
+ break;
+ case XLOG_BTREE_SPLIT_R:
+ id = "SPLIT_R";
+ break;
+ case XLOG_BTREE_SPLIT_L_ROOT:
+ id = "SPLIT_L_ROOT";
+ break;
+ case XLOG_BTREE_SPLIT_R_ROOT:
+ id = "SPLIT_R_ROOT";
+ break;
+ case XLOG_BTREE_VACUUM:
+ id = "VACUUM";
+ break;
+ case XLOG_BTREE_DELETE:
+ id = "DELETE";
+ break;
+ case XLOG_BTREE_MARK_PAGE_HALFDEAD:
+ id = "MARK_PAGE_HALFDEAD";
+ break;
+ case XLOG_BTREE_UNLINK_PAGE:
+ id = "UNLINK_PAGE";
+ break;
+ case XLOG_BTREE_UNLINK_PAGE_META:
+ id = "UNLINK_PAGE_META";
+ break;
+ case XLOG_BTREE_NEWROOT:
+ id = "NEWROOT";
+ break;
+ case XLOG_BTREE_REUSE_PAGE:
+ id = "REUSE_PAGE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/relmapdesc.c b/src/backend/access/rmgrdesc/relmapdesc.c
index 06fd4b3..2aebf22 100644
--- a/src/backend/access/rmgrdesc/relmapdesc.c
+++ b/src/backend/access/rmgrdesc/relmapdesc.c
@@ -32,3 +32,18 @@ relmap_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+relmap_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_RELMAP_UPDATE:
+ id = "UPDATE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/seqdesc.c b/src/backend/access/rmgrdesc/seqdesc.c
index 42eb9b9..157c7c6 100644
--- a/src/backend/access/rmgrdesc/seqdesc.c
+++ b/src/backend/access/rmgrdesc/seqdesc.c
@@ -35,3 +35,18 @@ seq_desc(StringInfo buf, XLogRecord *record)
appendStringInfo(buf, "rel %u/%u/%u",
xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
}
+
+const char *
+seq_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_SEQ_LOG:
+ id = "LOG";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/smgrdesc.c b/src/backend/access/rmgrdesc/smgrdesc.c
index c76c815..0a7a6e2 100644
--- a/src/backend/access/rmgrdesc/smgrdesc.c
+++ b/src/backend/access/rmgrdesc/smgrdesc.c
@@ -44,3 +44,21 @@ smgr_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+smgr_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_SMGR_CREATE:
+ id = "CREATE";
+ break;
+ case XLOG_SMGR_TRUNCATE:
+ id = "TRUNCATE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/spgdesc.c b/src/backend/access/rmgrdesc/spgdesc.c
index ed369b2..76f43ff 100644
--- a/src/backend/access/rmgrdesc/spgdesc.c
+++ b/src/backend/access/rmgrdesc/spgdesc.c
@@ -88,3 +88,42 @@ spg_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+spg_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_SPGIST_CREATE_INDEX:
+ id = "CREATE_INDEX";
+ break;
+ case XLOG_SPGIST_ADD_LEAF:
+ id = "ADD_LEAF";
+ break;
+ case XLOG_SPGIST_MOVE_LEAFS:
+ id = "MOVE_LEAFS";
+ break;
+ case XLOG_SPGIST_ADD_NODE:
+ id = "ADD_NODE";
+ break;
+ case XLOG_SPGIST_SPLIT_TUPLE:
+ id = "SPLIT_TUPLE";
+ break;
+ case XLOG_SPGIST_PICKSPLIT:
+ id = "PICKSPLIT";
+ break;
+ case XLOG_SPGIST_VACUUM_LEAF:
+ id = "VACUUM_LEAF";
+ break;
+ case XLOG_SPGIST_VACUUM_ROOT:
+ id = "VACUUM_ROOT";
+ break;
+ case XLOG_SPGIST_VACUUM_REDIRECT:
+ id = "VACUUM_REDIRECT";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/standbydesc.c b/src/backend/access/rmgrdesc/standbydesc.c
index a127d38..77503d4 100644
--- a/src/backend/access/rmgrdesc/standbydesc.c
+++ b/src/backend/access/rmgrdesc/standbydesc.c
@@ -64,3 +64,21 @@ standby_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+standby_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_STANDBY_LOCK:
+ id = "LOCK";
+ break;
+ case XLOG_RUNNING_XACTS:
+ id = "RUNNING_XACTS";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/tblspcdesc.c b/src/backend/access/rmgrdesc/tblspcdesc.c
index 30b1f06..c947845 100644
--- a/src/backend/access/rmgrdesc/tblspcdesc.c
+++ b/src/backend/access/rmgrdesc/tblspcdesc.c
@@ -39,3 +39,21 @@ tblspc_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+tblspc_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_TBLSPC_CREATE:
+ id = "CREATE";
+ break;
+ case XLOG_TBLSPC_DROP:
+ id = "DROP";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/xactdesc.c b/src/backend/access/rmgrdesc/xactdesc.c
index 994931e..8ea10c9 100644
--- a/src/backend/access/rmgrdesc/xactdesc.c
+++ b/src/backend/access/rmgrdesc/xactdesc.c
@@ -196,3 +196,36 @@ xact_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+xact_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_XACT_COMMIT:
+ id = "COMMIT";
+ break;
+ case XLOG_XACT_PREPARE:
+ id = "PREPARE";
+ break;
+ case XLOG_XACT_ABORT:
+ id = "ABORT";
+ break;
+ case XLOG_XACT_COMMIT_PREPARED:
+ id = "COMMIT_PREPARED";
+ break;
+ case XLOG_XACT_ABORT_PREPARED:
+ id = "ABORT_PREPARED";
+ break;
+ case XLOG_XACT_ASSIGNMENT:
+ id = "ASSIGNMENT";
+ break;
+ case XLOG_XACT_COMMIT_COMPACT:
+ id = "COMMIT_COMPACT";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/xlogdesc.c b/src/backend/access/rmgrdesc/xlogdesc.c
index 2224da1..04a1f24 100644
--- a/src/backend/access/rmgrdesc/xlogdesc.c
+++ b/src/backend/access/rmgrdesc/xlogdesc.c
@@ -144,3 +144,48 @@ xlog_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+xlog_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_CHECKPOINT_SHUTDOWN:
+ id = "CHECKPOINT_SHUTDOWN";
+ break;
+ case XLOG_CHECKPOINT_ONLINE:
+ id = "CHECKPOINT_ONLINE";
+ break;
+ case XLOG_NOOP:
+ id = "NOOP";
+ break;
+ case XLOG_NEXTOID:
+ id = "NEXTOID";
+ break;
+ case XLOG_SWITCH:
+ id = "SWITCH";
+ break;
+ case XLOG_BACKUP_END:
+ id = "BACKUP_END";
+ break;
+ case XLOG_PARAMETER_CHANGE:
+ id = "PARAMETER_CHANGE";
+ break;
+ case XLOG_RESTORE_POINT:
+ id = "RESTORE_POINT";
+ break;
+ case XLOG_FPW_CHANGE:
+ id = "FPW_CHANGE";
+ break;
+ case XLOG_END_OF_RECOVERY:
+ id = "END_OF_RECOVERY";
+ break;
+ case XLOG_FPI:
+ id = "FPI";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/transam/rmgr.c b/src/backend/access/transam/rmgr.c
index c0a7a6f..2645a7a 100644
--- a/src/backend/access/transam/rmgr.c
+++ b/src/backend/access/transam/rmgr.c
@@ -25,8 +25,8 @@
#include "utils/relmapper.h"
/* must be kept in sync with RmgrData definition in xlog_internal.h */
-#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \
- { name, redo, desc, startup, cleanup },
+#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \
+ { name, redo, desc, identify, startup, cleanup },
const RmgrData RmgrTable[RM_MAX_ID + 1] = {
#include "access/rmgrlist.h"
diff --git a/src/include/access/clog.h b/src/include/access/clog.h
index be9b867..8562631 100644
--- a/src/include/access/clog.h
+++ b/src/include/access/clog.h
@@ -49,5 +49,6 @@ extern void TruncateCLOG(TransactionId oldestXact);
extern void clog_redo(XLogRecPtr lsn, XLogRecord *record);
extern void clog_desc(StringInfo buf, XLogRecord *record);
+extern const char *clog_identify(uint8 info);
#endif /* CLOG_H */
diff --git a/src/include/access/gin.h b/src/include/access/gin.h
index a0b288d..0ebecb4 100644
--- a/src/include/access/gin.h
+++ b/src/include/access/gin.h
@@ -74,6 +74,7 @@ extern void ginUpdateStats(Relation index, const GinStatsData *stats);
/* ginxlog.c */
extern void gin_redo(XLogRecPtr lsn, XLogRecord *record);
extern void gin_desc(StringInfo buf, XLogRecord *record);
+extern const char *gin_identify(uint8 info);
extern void gin_xlog_startup(void);
extern void gin_xlog_cleanup(void);
diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h
index 03e9903..879f113 100644
--- a/src/include/access/gist_private.h
+++ b/src/include/access/gist_private.h
@@ -452,6 +452,7 @@ extern SplitedPageLayout *gistSplit(Relation r, Page page, IndexTuple *itup,
/* gistxlog.c */
extern void gist_redo(XLogRecPtr lsn, XLogRecord *record);
extern void gist_desc(StringInfo buf, XLogRecord *record);
+extern const char *gist_identify(uint8 info);
extern void gist_xlog_startup(void);
extern void gist_xlog_cleanup(void);
diff --git a/src/include/access/hash.h b/src/include/access/hash.h
index 42a1d94..950c1a4 100644
--- a/src/include/access/hash.h
+++ b/src/include/access/hash.h
@@ -357,5 +357,6 @@ extern OffsetNumber _hash_binsearch_last(Page page, uint32 hash_value);
/* hash.c */
extern void hash_redo(XLogRecPtr lsn, XLogRecord *record);
extern void hash_desc(StringInfo buf, XLogRecord *record);
+extern const char *hash_identify(uint8 info);
#endif /* HASH_H */
diff --git a/src/include/access/heapam_xlog.h b/src/include/access/heapam_xlog.h
index 05beb00..0e00a11 100644
--- a/src/include/access/heapam_xlog.h
+++ b/src/include/access/heapam_xlog.h
@@ -369,8 +369,10 @@ extern void HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple,
extern void heap_redo(XLogRecPtr lsn, XLogRecord *record);
extern void heap_desc(StringInfo buf, XLogRecord *record);
+extern const char *heap_identify(uint8 info);
extern void heap2_redo(XLogRecPtr lsn, XLogRecord *record);
extern void heap2_desc(StringInfo buf, XLogRecord *record);
+extern const char *heap2_identify(uint8 info);
extern void heap_xlog_logical_rewrite(XLogRecPtr lsn, XLogRecord *r);
extern XLogRecPtr log_heap_cleanup_info(RelFileNode rnode,
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index f6d2e04..1910e7a 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -136,6 +136,7 @@ extern void multixact_twophase_postabort(TransactionId xid, uint16 info,
extern void multixact_redo(XLogRecPtr lsn, XLogRecord *record);
extern void multixact_desc(StringInfo buf, XLogRecord *record);
+extern const char *multixact_identify(uint8 info);
extern char *mxid_to_string(MultiXactId multi, int nmembers,
MultiXactMember *members);
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
index 9fa943f..90fd6d0 100644
--- a/src/include/access/nbtree.h
+++ b/src/include/access/nbtree.h
@@ -726,5 +726,6 @@ extern void _bt_leafbuild(BTSpool *btspool, BTSpool *spool2);
*/
extern void btree_redo(XLogRecPtr lsn, XLogRecord *record);
extern void btree_desc(StringInfo buf, XLogRecord *record);
+extern const char *btree_identify(uint8 info);
#endif /* NBTREE_H */
diff --git a/src/include/access/spgist.h b/src/include/access/spgist.h
index 7f8655c..f218a83 100644
--- a/src/include/access/spgist.h
+++ b/src/include/access/spgist.h
@@ -198,6 +198,7 @@ extern Datum spgvacuumcleanup(PG_FUNCTION_ARGS);
/* spgxlog.c */
extern void spg_redo(XLogRecPtr lsn, XLogRecord *record);
extern void spg_desc(StringInfo buf, XLogRecord *record);
+extern const char *spg_identify(uint8 info);
extern void spg_xlog_startup(void);
extern void spg_xlog_cleanup(void);
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 10ee943..ff7c426 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -257,5 +257,6 @@ extern int xactGetCommittedChildren(TransactionId **ptr);
extern void xact_redo(XLogRecPtr lsn, XLogRecord *record);
extern void xact_desc(StringInfo buf, XLogRecord *record);
+extern const char *xact_identify(uint8 info);
#endif /* XACT_H */
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 85f9cb7..e16d43c 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -299,6 +299,7 @@ extern Buffer RestoreBackupBlock(XLogRecPtr lsn, XLogRecord *record,
extern void xlog_redo(XLogRecPtr lsn, XLogRecord *record);
extern void xlog_desc(StringInfo buf, XLogRecord *record);
+extern const char *xlog_identify(uint8 info);
extern void issue_xlog_fsync(int fd, XLogSegNo segno);
diff --git a/src/include/catalog/storage_xlog.h b/src/include/catalog/storage_xlog.h
index 7081c99..5fc7235 100644
--- a/src/include/catalog/storage_xlog.h
+++ b/src/include/catalog/storage_xlog.h
@@ -45,5 +45,6 @@ extern void log_smgrcreate(RelFileNode *rnode, ForkNumber forkNum);
extern void smgr_redo(XLogRecPtr lsn, XLogRecord *record);
extern void smgr_desc(StringInfo buf, XLogRecord *record);
+extern const char *smgr_identify(uint8 info);
#endif /* STORAGE_XLOG_H */
diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h
index c2380dc..811713f 100644
--- a/src/include/commands/dbcommands.h
+++ b/src/include/commands/dbcommands.h
@@ -64,6 +64,7 @@ extern char *get_database_name(Oid dbid);
extern void dbase_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void dbase_desc(StringInfo buf, XLogRecord *rptr);
+extern const char *dbase_identify(uint8 info);
extern void check_encoding_locale_matches(int encoding, const char *collate, const char *ctype);
diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h
index 8819c00..914d155 100644
--- a/src/include/commands/sequence.h
+++ b/src/include/commands/sequence.h
@@ -78,5 +78,6 @@ extern void ResetSequenceCaches(void);
extern void seq_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void seq_desc(StringInfo buf, XLogRecord *rptr);
+extern const char *seq_identify(uint8 info);
#endif /* SEQUENCE_H */
diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h
index 073cb0d..5823bd9 100644
--- a/src/include/commands/tablespace.h
+++ b/src/include/commands/tablespace.h
@@ -58,5 +58,6 @@ extern bool directory_is_empty(const char *path);
extern void tblspc_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void tblspc_desc(StringInfo buf, XLogRecord *rptr);
+extern const char *tblspc_identify(uint8 info);
#endif /* TABLESPACE_H */
diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h
index da22fd3..1c63af5 100644
--- a/src/include/storage/standby.h
+++ b/src/include/storage/standby.h
@@ -83,6 +83,7 @@ typedef struct xl_running_xacts
/* Recovery handlers for the Standby Rmgr (RM_STANDBY_ID) */
extern void standby_redo(XLogRecPtr lsn, XLogRecord *record);
extern void standby_desc(StringInfo buf, XLogRecord *record);
+extern const char *standby_identify(uint8 info);
/*
* Declarations for GetRunningTransactionData(). Similar to Snapshots, but
diff --git a/src/include/utils/relmapper.h b/src/include/utils/relmapper.h
index 76bcf18..37937dd 100644
--- a/src/include/utils/relmapper.h
+++ b/src/include/utils/relmapper.h
@@ -60,5 +60,6 @@ extern void RelationMapInitializePhase3(void);
extern void relmap_redo(XLogRecPtr lsn, XLogRecord *record);
extern void relmap_desc(StringInfo buf, XLogRecord *record);
+extern const char *relmap_identify(uint8 info);
#endif /* RELMAPPER_H */
0004-xlogdump.difftext/x-diff; charset=us-asciiDownload
diff --git a/doc/src/sgml/pg_xlogdump.sgml b/doc/src/sgml/pg_xlogdump.sgml
index 1d1a2ce..bfd9eb9 100644
--- a/doc/src/sgml/pg_xlogdump.sgml
+++ b/doc/src/sgml/pg_xlogdump.sgml
@@ -180,6 +180,28 @@ PostgreSQL documentation
</varlistentry>
<varlistentry>
+ <term><option>-z</option></term>
+ <term><option>--stats</option></term>
+ <listitem>
+ <para>
+ Display summary statistics (number and size of records and
+ full-page images per rmgr) instead of individual records.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-Z</option></term>
+ <term><option>--record-stats</option></term>
+ <listitem>
+ <para>
+ Display summary statistics (number and size of records and
+ full-page images) instead of individual records.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-?</></term>
<term><option>--help</></term>
<listitem>
diff --git a/contrib/pg_xlogdump/pg_xlogdump.c b/contrib/pg_xlogdump/pg_xlogdump.c
index c555786..3daf023 100644
--- a/contrib/pg_xlogdump/pg_xlogdump.c
+++ b/contrib/pg_xlogdump/pg_xlogdump.c
@@ -15,9 +15,10 @@
#include <dirent.h>
#include <unistd.h>
-#include "access/xlog.h"
#include "access/xlogreader.h"
#include "access/transam.h"
+#include "catalog/pg_control.h"
+#include "catalog/storage_xlog.h"
#include "common/fe_memutils.h"
#include "getopt_long.h"
#include "rmgrdesc.h"
@@ -41,6 +42,8 @@ typedef struct XLogDumpConfig
int stop_after_records;
int already_displayed_records;
bool follow;
+ bool stats;
+ bool stats_per_record;
/* filter options */
int filter_by_rmgr;
@@ -48,6 +51,20 @@ typedef struct XLogDumpConfig
bool filter_by_xid_enabled;
} XLogDumpConfig;
+typedef struct Stats
+{
+ uint64 count;
+ uint64 rec_len;
+ uint64 fpi_len;
+} Stats;
+
+typedef struct XLogDumpStats
+{
+ uint64 count;
+ Stats rmgr_stats[RM_NEXT_ID];
+ Stats record_stats[RM_NEXT_ID][16];
+} XLogDumpStats;
+
static void
fatal_error(const char *fmt,...)
__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
@@ -322,6 +339,50 @@ XLogDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen,
}
/*
+ * Store per-rmgr and per-record statistics for a given record.
+ */
+static void
+XLogDumpCountRecord(XLogDumpConfig *config, XLogDumpStats *stats, XLogRecPtr ReadRecPtr, XLogRecord *record)
+{
+ RmgrId rmid;
+ uint8 recid;
+
+ if (config->filter_by_rmgr != -1 &&
+ config->filter_by_rmgr != record->xl_rmid)
+ return;
+
+ if (config->filter_by_xid_enabled &&
+ config->filter_by_xid != record->xl_xid)
+ return;
+
+ stats->count++;
+
+ /* Update per-rmgr statistics */
+
+ rmid = record->xl_rmid;
+
+ stats->rmgr_stats[rmid].count++;
+ stats->rmgr_stats[rmid].rec_len +=
+ record->xl_len + SizeOfXLogRecord;
+ stats->rmgr_stats[rmid].fpi_len +=
+ record->xl_tot_len - (record->xl_len + SizeOfXLogRecord);
+
+ /*
+ * Update per-record statistics, where the record is identified by a
+ * combination of the RmgrId and the upper four bits of the xl_info
+ * field (to give sixteen possible entries per RmgrId).
+ */
+
+ recid = (record->xl_info & ~XLR_INFO_MASK) >> 4;
+
+ stats->record_stats[rmid][recid].count++;
+ stats->record_stats[rmid][recid].rec_len +=
+ record->xl_len + SizeOfXLogRecord;
+ stats->record_stats[rmid][recid].fpi_len +=
+ record->xl_tot_len - (record->xl_len + SizeOfXLogRecord);
+}
+
+/*
* Print a record to stdout
*/
static void
@@ -380,6 +441,132 @@ XLogDumpDisplayRecord(XLogDumpConfig *config, XLogRecPtr ReadRecPtr, XLogRecord
}
}
+/*
+ * Display a single row of record counts and sizes for an rmgr or record.
+ */
+static void
+XLogDumpStatsRow(const char *name,
+ uint64 n, double n_pct,
+ uint64 rec_len, double rec_len_pct,
+ uint64 fpi_len, double fpi_len_pct,
+ uint64 total_len, double total_len_pct)
+{
+ printf("%-27s "
+ "%20" INT64_MODIFIER "u (%6.02f) "
+ "%20" INT64_MODIFIER "u (%6.02f) "
+ "%20" INT64_MODIFIER "u (%6.02f) "
+ "%20" INT64_MODIFIER "u (%6.02f)\n",
+ name, n, n_pct, rec_len, rec_len_pct, fpi_len, fpi_len_pct,
+ total_len, total_len_pct);
+}
+
+
+/*
+ * Display summary statistics about the records seen so far.
+ */
+static void
+XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats)
+{
+ int ri, rj;
+ uint64 total_count = 0;
+ uint64 total_rec_len = 0;
+ uint64 total_fpi_len = 0;
+ uint64 total_len = 0;
+
+ /*
+ * Make a first pass to calculate column totals:
+ * count(*),
+ * sum(xl_len+SizeOfXLogRecord),
+ * sum(xl_tot_len-xl_len-SizeOfXLogRecord), and
+ * sum(xl_tot_len).
+ * These are used to calculate percentages for each record type.
+ */
+
+ for (ri = 0; ri < RM_NEXT_ID; ri++)
+ {
+ total_count += stats->rmgr_stats[ri].count;
+ total_rec_len += stats->rmgr_stats[ri].rec_len;
+ total_fpi_len += stats->rmgr_stats[ri].fpi_len;
+ }
+ total_len = total_rec_len+total_fpi_len;
+
+ /*
+ * 27 is strlen("Transaction/COMMIT_PREPARED"),
+ * 20 is strlen(2^64), 8 is strlen("(100.00%)")
+ */
+
+ printf("%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n"
+ "%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n",
+ "Type", "N", "(%)", "Record size", "(%)", "FPI size", "(%)", "Combined size", "(%)",
+ "----", "-", "---", "-----------", "---", "--------", "---", "-------------", "---");
+
+ for (ri = 0; ri < RM_NEXT_ID; ri++)
+ {
+ uint64 count, rec_len, fpi_len, tot_len;
+ const RmgrDescData *desc = &RmgrDescTable[ri];
+
+ if (!config->stats_per_record)
+ {
+ count = stats->rmgr_stats[ri].count;
+ rec_len = stats->rmgr_stats[ri].rec_len;
+ fpi_len = stats->rmgr_stats[ri].fpi_len;
+ tot_len = rec_len + fpi_len;
+
+ XLogDumpStatsRow(desc->rm_name,
+ count, 100 * (double)count / total_count,
+ rec_len, 100 * (double)rec_len / total_rec_len,
+ fpi_len, 100 * (double)fpi_len / total_fpi_len,
+ tot_len, 100 * (double)tot_len / total_len);
+ }
+ else
+ {
+ for (rj = 0; rj < 16; rj++)
+ {
+ const char *id;
+
+ count = stats->record_stats[ri][rj].count;
+ rec_len = stats->record_stats[ri][rj].rec_len;
+ fpi_len = stats->record_stats[ri][rj].fpi_len;
+ tot_len = rec_len + fpi_len;
+
+ /* Skip undefined combinations and ones that didn't occur */
+ if (count == 0)
+ continue;
+
+ id = desc->rm_identify(rj << 4);
+ if (id == NULL)
+ id = psprintf("0x%x", rj << 4);
+
+ XLogDumpStatsRow(psprintf("%s/%s", desc->rm_name, id),
+ count, 100 * (double)count / total_count,
+ rec_len, 100 * (double)rec_len / total_rec_len,
+ fpi_len, 100 * (double)fpi_len / total_fpi_len,
+ tot_len, 100 * (double)tot_len / total_len);
+ }
+ }
+ }
+
+ printf("%-27s %20s %8s %20s %8s %20s %8s %20s\n",
+ "", "--------", "", "--------", "", "--------", "", "--------");
+
+ /*
+ * The percentages in earlier rows were calculated against the
+ * column total, but the ones that follow are against the row total.
+ * Note that these are displayed with a % symbol to differentiate
+ * them from the earlier ones, and are thus up to 9 characters long.
+ */
+
+ printf("%-27s "
+ "%20" INT64_MODIFIER "u %-9s"
+ "%20" INT64_MODIFIER "u %-9s"
+ "%20" INT64_MODIFIER "u %-9s"
+ "%20" INT64_MODIFIER "u %-6s\n",
+ "Total", stats->count, "",
+ total_rec_len, psprintf("[%.02f%%]", 100 * (double)total_rec_len / total_len),
+ total_fpi_len, psprintf("[%.02f%%]", 100 * (double)total_fpi_len / total_len),
+ total_len, "[100%]");
+}
+
static void
usage(void)
{
@@ -401,6 +588,8 @@ usage(void)
printf(" (default: 1 or the value used in STARTSEG)\n");
printf(" -V, --version output version information, then exit\n");
printf(" -x, --xid=XID only show records with TransactionId XID\n");
+ printf(" -z, --stats show per-rmgr statistics\n");
+ printf(" -Z, --record-stats show per-record statistics\n");
printf(" -?, --help show this help, then exit\n");
}
@@ -412,6 +601,7 @@ main(int argc, char **argv)
XLogReaderState *xlogreader_state;
XLogDumpPrivate private;
XLogDumpConfig config;
+ XLogDumpStats stats;
XLogRecord *record;
XLogRecPtr first_record;
char *errormsg;
@@ -428,6 +618,8 @@ main(int argc, char **argv)
{"timeline", required_argument, NULL, 't'},
{"xid", required_argument, NULL, 'x'},
{"version", no_argument, NULL, 'V'},
+ {"stats", no_argument, NULL, 'z'},
+ {"record-stats", no_argument, NULL, 'Z'},
{NULL, 0, NULL, 0}
};
@@ -438,6 +630,7 @@ main(int argc, char **argv)
memset(&private, 0, sizeof(XLogDumpPrivate));
memset(&config, 0, sizeof(XLogDumpConfig));
+ memset(&stats, 0, sizeof(XLogDumpStats));
private.timeline = 1;
private.startptr = InvalidXLogRecPtr;
@@ -451,6 +644,8 @@ main(int argc, char **argv)
config.filter_by_rmgr = -1;
config.filter_by_xid = InvalidTransactionId;
config.filter_by_xid_enabled = false;
+ config.stats = false;
+ config.stats_per_record = false;
if (argc <= 1)
{
@@ -458,7 +653,7 @@ main(int argc, char **argv)
goto bad_argument;
}
- while ((option = getopt_long(argc, argv, "be:?fn:p:r:s:t:Vx:",
+ while ((option = getopt_long(argc, argv, "be:?fn:p:r:s:t:Vx:zZ",
long_options, &optindex)) != -1)
{
switch (option)
@@ -551,6 +746,13 @@ main(int argc, char **argv)
}
config.filter_by_xid_enabled = true;
break;
+ case 'z':
+ config.stats = true;
+ break;
+ case 'Z':
+ config.stats = true;
+ config.stats_per_record = true;
+ break;
default:
goto bad_argument;
}
@@ -711,7 +913,10 @@ main(int argc, char **argv)
/* after reading the first record, continue at next one */
first_record = InvalidXLogRecPtr;
- XLogDumpDisplayRecord(&config, xlogreader_state->ReadRecPtr, record);
+ if (config.stats == true)
+ XLogDumpCountRecord(&config, &stats, xlogreader_state->ReadRecPtr, record);
+ else
+ XLogDumpDisplayRecord(&config, xlogreader_state->ReadRecPtr, record);
/* check whether we printed enough */
if (config.stop_after_records > 0 &&
@@ -719,6 +924,9 @@ main(int argc, char **argv)
break;
}
+ if (config.stats == true)
+ XLogDumpDisplayStats(&config, &stats);
+
if (errormsg)
fatal_error("error in WAL record at %X/%X: %s\n",
(uint32) (xlogreader_state->ReadRecPtr >> 32),
On 07/07/2014 10:32 PM, Abhijit Menon-Sen wrote:
At 2014-07-07 09:48:44 +0200, andres@2ndquadrant.com wrote:
I'd suggest only defining INT64_MODIFIER here and build INT64_FORMAT,
UINT64_FORMAT ontop, in c.h.Oh, I see. I'm sorry, I misread your earlier suggestion. Regenerated
patches attached. Is this what you had in mind?
Committed the patch to add INT64_MODIFIER, with minor fixes.
The new rm_identify method needs to be documented. Not sure where;
surprisingly I can't find any documentation on the existing methods
either. Perhaps add comments to the RmgrData struct, explaining all of
the methods. In particular, should give guidelines on what output
belongs in rm_desc and what in rm_identify.
I think the names that rm_identify returns should match those that the
rm_desc functions print. As the patch stands, for example when heap_desc
prints out something like:
hot_update(init): xmax 123; new tid 1/2 xmax 456
The corresponding rm_identify output is:
HOT_UPDATE+INIT
It would be better to spell them the same, so that when you look at the
summary stats and the raw pg_xlogdump output, you can tell which records
contributed to which summary line.
- Heikki
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
At 2014-08-21 10:06:39 +0300, hlinnakangas@vmware.com wrote:
Committed the patch to add INT64_MODIFIER, with minor fixes.
Thank you.
The new rm_identify method needs to be documented. […]
Perhaps add comments to the RmgrData struct, explaining
all of the methods.
OK, I'll submit a patch to add these comments.
I think the names that rm_identify returns should match those that the
rm_desc functions print.
I had originally started off trying to keep the output in sync, but it
doesn't work very well. There are rm_desc functions that print things
like "truncate before" and "Create posting tree", and many decisions
are quite arbitrary ("freeze_page", "cleanup info", "multi-insert").
I think it's better the (grep-friendly) way it is. If anything, perhaps
rm_desc should output "${rm_identify}[: optional explanation]". That
would also make it very clear what should go in rm_identify and what
should go in rm_desc.
Thoughts?
The corresponding rm_identify output is:
HOT_UPDATE+INIT
The +INIT is admittedly a special case, and I would have no objection to
writing that as (INIT) or something instead.
-- Abhijit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 09/11/2014 11:43 AM, Abhijit Menon-Sen wrote:
At 2014-08-21 10:06:39 +0300, hlinnakangas@vmware.com wrote:
I think the names that rm_identify returns should match those that the
rm_desc functions print.I had originally started off trying to keep the output in sync, but it
doesn't work very well. There are rm_desc functions that print things
like "truncate before" and "Create posting tree", and many decisions
are quite arbitrary ("freeze_page", "cleanup info", "multi-insert").
It would be good to clean up those messages to be more sensible and
consistent.
I think it's better the (grep-friendly) way it is. If anything, perhaps
rm_desc should output "${rm_identify}[: optional explanation]". That
would also make it very clear what should go in rm_identify and what
should go in rm_desc.
Yeah, that makes sense too.
The corresponding rm_identify output is:
HOT_UPDATE+INIT
The +INIT is admittedly a special case, and I would have no objection to
writing that as (INIT) or something instead.
I don't care much, as long as it's consistent the rm_desc output.
It's quite arbitrary that the INIT cases are considered different record
types, with their own "identity" string, instead of being just a flag in
the same record type. It's an implementation detail that that flag is
stored in the xl_info, and that implementation detail is now exposed in
the stats pg_xlogdump --stats output. There are similar cases in B-tree
splits, for example, where a split where the new tuple goes to the left
half is considered a different record type than one where it goes ot the
right half. It might be interesting to count them separately in the
stats, but then again it might just be confusing. The xl_info flags and
the rm_desc output were never intended to be a useful categorization for
statistics purposes, so it's not surprising that it's not too well
suited for that. Nevertheless, the "pg_xlogdump --stats" is useful as it
is, if you know the limitations.
- Heikki
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2014-09-11 12:14:42 +0300, Heikki Linnakangas wrote:
On 09/11/2014 11:43 AM, Abhijit Menon-Sen wrote:
At 2014-08-21 10:06:39 +0300, hlinnakangas@vmware.com wrote:
I think the names that rm_identify returns should match those that the
rm_desc functions print.I had originally started off trying to keep the output in sync, but it
doesn't work very well. There are rm_desc functions that print things
like "truncate before" and "Create posting tree", and many decisions
are quite arbitrary ("freeze_page", "cleanup info", "multi-insert").It would be good to clean up those messages to be more sensible and
consistent.
I think it's better the (grep-friendly) way it is. If anything, perhaps
rm_desc should output "${rm_identify}[: optional explanation]". That
would also make it very clear what should go in rm_identify and what
should go in rm_desc.
Yeah, that makes sense too.
I'm not sure I agree here. From a theoretical POV sure, but wouldn't
that lead to even longer lines for xlogdump and other error messages for
some records?
We probably need to see how it plays out.
The corresponding rm_identify output is:
HOT_UPDATE+INIT
The +INIT is admittedly a special case, and I would have no objection to
writing that as (INIT) or something instead.I don't care much, as long as it's consistent the rm_desc output.
It's quite arbitrary that the INIT cases are considered different record
types, with their own "identity" string, instead of being just a flag in the
same record type. It's an implementation detail that that flag is stored in
the xl_info, and that implementation detail is now exposed in the stats
pg_xlogdump --stats output.
It's also actually quite good from a display purpose. +INIT will have
quite different wal logging characteristics :)
There are similar cases in B-tree splits, for
example, where a split where the new tuple goes to the left half is
considered a different record type than one where it goes ot the right half.
It might be interesting to count them separately in the stats, but then
again it might just be confusing. The xl_info flags and the rm_desc output
were never intended to be a useful categorization for statistics purposes,
so it's not surprising that it's not too well suited for that. Nevertheless,
the "pg_xlogdump --stats" is useful as it is, if you know the limitations.
I agree it's not perfect, but I think it's a huge step forward. We very
well might want to improve upon the stats granularity once in, but I
think it already gives a fair amount of direction where to look.
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 09/11/2014 12:22 PM, Andres Freund wrote:
On 2014-09-11 12:14:42 +0300, Heikki Linnakangas wrote:
On 09/11/2014 11:43 AM, Abhijit Menon-Sen wrote:
At 2014-08-21 10:06:39 +0300, hlinnakangas@vmware.com wrote:
I think the names that rm_identify returns should match those that the
rm_desc functions print.I had originally started off trying to keep the output in sync, but it
doesn't work very well. There are rm_desc functions that print things
like "truncate before" and "Create posting tree", and many decisions
are quite arbitrary ("freeze_page", "cleanup info", "multi-insert").It would be good to clean up those messages to be more sensible and
consistent.I think it's better the (grep-friendly) way it is. If anything, perhaps
rm_desc should output "${rm_identify}[: optional explanation]". That
would also make it very clear what should go in rm_identify and what
should go in rm_desc.Yeah, that makes sense too.
I'm not sure I agree here. From a theoretical POV sure, but wouldn't
that lead to even longer lines for xlogdump and other error messages for
some records?
No. All the rm_desc functions already follow that convention, and print
"foo: details", where "foo" identifies the record type based on xl_info.
This proposal would just make that convention more official, and
stipulate that the "foo" part should match what the new rm_identify()
function returns. (Or perhaps even better, define it so that rm_desc
prints only the "details" part, and rm_identify() the "foo" part, and
have the callers put the two strings together if they want)
There are similar cases in B-tree splits, for
example, where a split where the new tuple goes to the left half is
considered a different record type than one where it goes ot the right half.
It might be interesting to count them separately in the stats, but then
again it might just be confusing. The xl_info flags and the rm_desc output
were never intended to be a useful categorization for statistics purposes,
so it's not surprising that it's not too well suited for that. Nevertheless,
the "pg_xlogdump --stats" is useful as it is, if you know the limitations.I agree it's not perfect, but I think it's a huge step forward. We very
well might want to improve upon the stats granularity once in, but I
think it already gives a fair amount of direction where to look.
Agreed. That's what I was also trying to say.
- Heikki
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hi.
I've attached two patches here:
0001-Make-pg_xlogdump-record-stats-display-summary-statis.patch is my
earlier patch to pg_xlogdump, rebased to master. It introduces the new
rm_identify callback, but doesn't touch rm_desc. Other than rebasing to
master after the INT64_FORMAT changes, I haven't changed anything.
0002-Clearly-separate-rm_identify-and-rm_desc-outputs.patch then makes
the change you (Heikki) wanted to see: rm_identify returns a name, and
rm_desc can be used to obtain optional additional detail, and xlog.c
just glues the two together in a new xlog_outdesc function. rm_desc
is changed largely only to (a) remove the "prefix: ", and (b) not
append UNKNOWN for unidentified records.
(I've done a little cleaning-up in the second patch, e.g. nbtdesc.c had
a bunch of repeated cases that I've unified, which seems a pretty nice
readability improvement overall.)
Good enough?
-- Abhijit
Attachments:
0001-Make-pg_xlogdump-record-stats-display-summary-statis.patchtext/x-diff; charset=us-asciiDownload
>From a85a5906733ca1324f7fceb6c4ff5b968a70532e Mon Sep 17 00:00:00 2001
From: Abhijit Menon-Sen <ams@2ndQuadrant.com>
Date: Wed, 4 Jun 2014 14:22:33 +0530
Subject: Make 'pg_xlogdump --[record-]stats' display summary statistics
---
configure | 2 +-
configure.in | 2 +-
contrib/pg_xlogdump/pg_xlogdump.c | 207 +++++++++++++++++++++++++++++-
contrib/pg_xlogdump/rmgrdesc.c | 4 +-
contrib/pg_xlogdump/rmgrdesc.h | 1 +
doc/src/sgml/pg_xlogdump.sgml | 22 ++++
src/backend/access/rmgrdesc/clogdesc.c | 18 +++
src/backend/access/rmgrdesc/dbasedesc.c | 18 +++
src/backend/access/rmgrdesc/gindesc.c | 42 ++++++
src/backend/access/rmgrdesc/gistdesc.c | 21 +++
src/backend/access/rmgrdesc/hashdesc.c | 6 +
src/backend/access/rmgrdesc/heapdesc.c | 83 ++++++++++++
src/backend/access/rmgrdesc/mxactdesc.c | 21 +++
src/backend/access/rmgrdesc/nbtdesc.c | 54 ++++++++
src/backend/access/rmgrdesc/relmapdesc.c | 15 +++
src/backend/access/rmgrdesc/seqdesc.c | 15 +++
src/backend/access/rmgrdesc/smgrdesc.c | 18 +++
src/backend/access/rmgrdesc/spgdesc.c | 39 ++++++
src/backend/access/rmgrdesc/standbydesc.c | 18 +++
src/backend/access/rmgrdesc/tblspcdesc.c | 18 +++
src/backend/access/rmgrdesc/xactdesc.c | 33 +++++
src/backend/access/rmgrdesc/xlogdesc.c | 45 +++++++
src/backend/access/transam/rmgr.c | 4 +-
src/include/access/clog.h | 1 +
src/include/access/gin.h | 1 +
src/include/access/gist_private.h | 1 +
src/include/access/hash.h | 1 +
src/include/access/heapam_xlog.h | 2 +
src/include/access/multixact.h | 1 +
src/include/access/nbtree.h | 1 +
src/include/access/rmgr.h | 2 +-
src/include/access/rmgrlist.h | 34 ++---
src/include/access/spgist.h | 1 +
src/include/access/xact.h | 1 +
src/include/access/xlog.h | 1 +
src/include/access/xlog_internal.h | 1 +
src/include/c.h | 3 +
src/include/catalog/storage_xlog.h | 1 +
src/include/commands/dbcommands.h | 1 +
src/include/commands/sequence.h | 1 +
src/include/commands/tablespace.h | 1 +
src/include/storage/standby.h | 1 +
src/include/utils/relmapper.h | 1 +
43 files changed, 736 insertions(+), 27 deletions(-)
diff --git a/configure b/configure
index dac8e49..22eb857 100755
--- a/configure
+++ b/configure
@@ -13091,7 +13091,7 @@ fi
# If we found "long int" is 64 bits, assume snprintf handles it. If
# we found we need to use "long long int", better check. We cope with
# snprintfs that use %lld, %qd, or %I64d as the format. If none of these
-# work, fall back to our own snprintf emulation (which we know uses %lld).
+# works, fall back to our own snprintf emulation (which we know uses %lld).
if test "$HAVE_LONG_LONG_INT_64" = yes ; then
if test $pgac_need_repl_snprintf = no; then
diff --git a/configure.in b/configure.in
index 1392277..c3c458c 100644
--- a/configure.in
+++ b/configure.in
@@ -1637,7 +1637,7 @@ fi
# If we found "long int" is 64 bits, assume snprintf handles it. If
# we found we need to use "long long int", better check. We cope with
# snprintfs that use %lld, %qd, or %I64d as the format. If none of these
-# work, fall back to our own snprintf emulation (which we know uses %lld).
+# works, fall back to our own snprintf emulation (which we know uses %lld).
if test "$HAVE_LONG_LONG_INT_64" = yes ; then
if test $pgac_need_repl_snprintf = no; then
diff --git a/contrib/pg_xlogdump/pg_xlogdump.c b/contrib/pg_xlogdump/pg_xlogdump.c
index c555786..11da5a8 100644
--- a/contrib/pg_xlogdump/pg_xlogdump.c
+++ b/contrib/pg_xlogdump/pg_xlogdump.c
@@ -15,9 +15,10 @@
#include <dirent.h>
#include <unistd.h>
-#include "access/xlog.h"
#include "access/xlogreader.h"
#include "access/transam.h"
+#include "catalog/pg_control.h"
+#include "catalog/storage_xlog.h"
#include "common/fe_memutils.h"
#include "getopt_long.h"
#include "rmgrdesc.h"
@@ -41,6 +42,8 @@ typedef struct XLogDumpConfig
int stop_after_records;
int already_displayed_records;
bool follow;
+ bool stats;
+ bool stats_per_record;
/* filter options */
int filter_by_rmgr;
@@ -48,6 +51,20 @@ typedef struct XLogDumpConfig
bool filter_by_xid_enabled;
} XLogDumpConfig;
+typedef struct Stats
+{
+ uint64 count;
+ uint64 rec_len;
+ uint64 fpi_len;
+} Stats;
+
+typedef struct XLogDumpStats
+{
+ uint64 count;
+ Stats rmgr_stats[RM_NEXT_ID];
+ Stats record_stats[RM_NEXT_ID][16];
+} XLogDumpStats;
+
static void
fatal_error(const char *fmt,...)
__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
@@ -322,6 +339,50 @@ XLogDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen,
}
/*
+ * Store per-rmgr and per-record statistics for a given record.
+ */
+static void
+XLogDumpCountRecord(XLogDumpConfig *config, XLogDumpStats *stats, XLogRecPtr ReadRecPtr, XLogRecord *record)
+{
+ RmgrId rmid;
+ uint8 recid;
+
+ if (config->filter_by_rmgr != -1 &&
+ config->filter_by_rmgr != record->xl_rmid)
+ return;
+
+ if (config->filter_by_xid_enabled &&
+ config->filter_by_xid != record->xl_xid)
+ return;
+
+ stats->count++;
+
+ /* Update per-rmgr statistics */
+
+ rmid = record->xl_rmid;
+
+ stats->rmgr_stats[rmid].count++;
+ stats->rmgr_stats[rmid].rec_len +=
+ record->xl_len + SizeOfXLogRecord;
+ stats->rmgr_stats[rmid].fpi_len +=
+ record->xl_tot_len - (record->xl_len + SizeOfXLogRecord);
+
+ /*
+ * Update per-record statistics, where the record is identified by a
+ * combination of the RmgrId and the upper four bits of the xl_info
+ * field (to give sixteen possible entries per RmgrId).
+ */
+
+ recid = (record->xl_info & ~XLR_INFO_MASK) >> 4;
+
+ stats->record_stats[rmid][recid].count++;
+ stats->record_stats[rmid][recid].rec_len +=
+ record->xl_len + SizeOfXLogRecord;
+ stats->record_stats[rmid][recid].fpi_len +=
+ record->xl_tot_len - (record->xl_len + SizeOfXLogRecord);
+}
+
+/*
* Print a record to stdout
*/
static void
@@ -380,6 +441,125 @@ XLogDumpDisplayRecord(XLogDumpConfig *config, XLogRecPtr ReadRecPtr, XLogRecord
}
}
+/*
+ * Display a single row of record counts and sizes for an rmgr or record.
+ */
+static void
+XLogDumpStatsRow(const char *name,
+ uint64 n, double n_pct,
+ uint64 rec_len, double rec_len_pct,
+ uint64 fpi_len, double fpi_len_pct,
+ uint64 total_len, double total_len_pct)
+{
+ printf("%-27s %20zu (%6.02f) %20zu (%6.02f) %20zu (%6.02f) %20zu (%6.02f)\n",
+ name, n, n_pct, rec_len, rec_len_pct, fpi_len, fpi_len_pct,
+ total_len, total_len_pct);
+}
+
+
+/*
+ * Display summary statistics about the records seen so far.
+ */
+static void
+XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats)
+{
+ int ri, rj;
+ uint64 total_count = 0;
+ uint64 total_rec_len = 0;
+ uint64 total_fpi_len = 0;
+ uint64 total_len = 0;
+
+ /*
+ * Make a first pass to calculate column totals:
+ * count(*),
+ * sum(xl_len+SizeOfXLogRecord),
+ * sum(xl_tot_len-xl_len-SizeOfXLogRecord), and
+ * sum(xl_tot_len).
+ * These are used to calculate percentages for each record type.
+ */
+
+ for (ri = 0; ri < RM_NEXT_ID; ri++)
+ {
+ total_count += stats->rmgr_stats[ri].count;
+ total_rec_len += stats->rmgr_stats[ri].rec_len;
+ total_fpi_len += stats->rmgr_stats[ri].fpi_len;
+ }
+ total_len = total_rec_len+total_fpi_len;
+
+ /*
+ * 27 is strlen("Transaction/COMMIT_PREPARED"),
+ * 20 is strlen(2^64), 8 is strlen("(100.00%)")
+ */
+
+ printf("%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n"
+ "%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n",
+ "Type", "N", "(%)", "Record size", "(%)", "FPI size", "(%)", "Combined size", "(%)",
+ "----", "-", "---", "-----------", "---", "--------", "---", "-------------", "---");
+
+ for (ri = 0; ri < RM_NEXT_ID; ri++)
+ {
+ uint64 count, rec_len, fpi_len, tot_len;
+ const RmgrDescData *desc = &RmgrDescTable[ri];
+
+ if (!config->stats_per_record)
+ {
+ count = stats->rmgr_stats[ri].count;
+ rec_len = stats->rmgr_stats[ri].rec_len;
+ fpi_len = stats->rmgr_stats[ri].fpi_len;
+ tot_len = rec_len + fpi_len;
+
+ XLogDumpStatsRow(desc->rm_name,
+ count, 100 * (double)count / total_count,
+ rec_len, 100 * (double)rec_len / total_rec_len,
+ fpi_len, 100 * (double)fpi_len / total_fpi_len,
+ tot_len, 100 * (double)tot_len / total_len);
+ }
+ else
+ {
+ for (rj = 0; rj < 16; rj++)
+ {
+ const char *id;
+
+ count = stats->record_stats[ri][rj].count;
+ rec_len = stats->record_stats[ri][rj].rec_len;
+ fpi_len = stats->record_stats[ri][rj].fpi_len;
+ tot_len = rec_len + fpi_len;
+
+ /* Skip undefined combinations and ones that didn't occur */
+ if (count == 0)
+ continue;
+
+ id = desc->rm_identify(rj << 4);
+ if (id == NULL)
+ id = psprintf("0x%x", rj << 4);
+
+ XLogDumpStatsRow(psprintf("%s/%s", desc->rm_name, id),
+ count, 100 * (double)count / total_count,
+ rec_len, 100 * (double)rec_len / total_rec_len,
+ fpi_len, 100 * (double)fpi_len / total_fpi_len,
+ tot_len, 100 * (double)tot_len / total_len);
+ }
+ }
+ }
+
+ printf("%-27s %20s %8s %20s %8s %20s %8s %20s\n",
+ "", "--------", "", "--------", "", "--------", "", "--------");
+
+ /*
+ * The percentages in earlier rows were calculated against the
+ * column total, but the ones that follow are against the row total.
+ * Note that these are displayed with a % symbol to differentiate
+ * them from the earlier ones, and are thus up to 9 characters long.
+ */
+
+ printf("%-27s %20zu %-9s%20zu %-9s%20zu %-9s%20zu %-6s\n",
+ "Total",
+ stats->count, "",
+ total_rec_len, psprintf("[%.02f%%]", 100 * (double)total_rec_len / total_len),
+ total_fpi_len, psprintf("[%.02f%%]", 100 * (double)total_fpi_len / total_len),
+ total_len, "[100%]");
+}
+
static void
usage(void)
{
@@ -401,6 +581,8 @@ usage(void)
printf(" (default: 1 or the value used in STARTSEG)\n");
printf(" -V, --version output version information, then exit\n");
printf(" -x, --xid=XID only show records with TransactionId XID\n");
+ printf(" -z, --stats show per-rmgr statistics\n");
+ printf(" -Z, --record-stats show per-record statistics\n");
printf(" -?, --help show this help, then exit\n");
}
@@ -412,6 +594,7 @@ main(int argc, char **argv)
XLogReaderState *xlogreader_state;
XLogDumpPrivate private;
XLogDumpConfig config;
+ XLogDumpStats stats;
XLogRecord *record;
XLogRecPtr first_record;
char *errormsg;
@@ -428,6 +611,8 @@ main(int argc, char **argv)
{"timeline", required_argument, NULL, 't'},
{"xid", required_argument, NULL, 'x'},
{"version", no_argument, NULL, 'V'},
+ {"stats", no_argument, NULL, 'z'},
+ {"record-stats", no_argument, NULL, 'Z'},
{NULL, 0, NULL, 0}
};
@@ -438,6 +623,7 @@ main(int argc, char **argv)
memset(&private, 0, sizeof(XLogDumpPrivate));
memset(&config, 0, sizeof(XLogDumpConfig));
+ memset(&stats, 0, sizeof(XLogDumpStats));
private.timeline = 1;
private.startptr = InvalidXLogRecPtr;
@@ -451,6 +637,8 @@ main(int argc, char **argv)
config.filter_by_rmgr = -1;
config.filter_by_xid = InvalidTransactionId;
config.filter_by_xid_enabled = false;
+ config.stats = false;
+ config.stats_per_record = false;
if (argc <= 1)
{
@@ -458,7 +646,7 @@ main(int argc, char **argv)
goto bad_argument;
}
- while ((option = getopt_long(argc, argv, "be:?fn:p:r:s:t:Vx:",
+ while ((option = getopt_long(argc, argv, "be:?fn:p:r:s:t:Vx:zZ",
long_options, &optindex)) != -1)
{
switch (option)
@@ -551,6 +739,13 @@ main(int argc, char **argv)
}
config.filter_by_xid_enabled = true;
break;
+ case 'z':
+ config.stats = true;
+ break;
+ case 'Z':
+ config.stats = true;
+ config.stats_per_record = true;
+ break;
default:
goto bad_argument;
}
@@ -711,7 +906,10 @@ main(int argc, char **argv)
/* after reading the first record, continue at next one */
first_record = InvalidXLogRecPtr;
- XLogDumpDisplayRecord(&config, xlogreader_state->ReadRecPtr, record);
+ if (config.stats == true)
+ XLogDumpCountRecord(&config, &stats, xlogreader_state->ReadRecPtr, record);
+ else
+ XLogDumpDisplayRecord(&config, xlogreader_state->ReadRecPtr, record);
/* check whether we printed enough */
if (config.stop_after_records > 0 &&
@@ -719,6 +917,9 @@ main(int argc, char **argv)
break;
}
+ if (config.stats == true)
+ XLogDumpDisplayStats(&config, &stats);
+
if (errormsg)
fatal_error("error in WAL record at %X/%X: %s\n",
(uint32) (xlogreader_state->ReadRecPtr >> 32),
diff --git a/contrib/pg_xlogdump/rmgrdesc.c b/contrib/pg_xlogdump/rmgrdesc.c
index cbcaaa6..dc27fd1 100644
--- a/contrib/pg_xlogdump/rmgrdesc.c
+++ b/contrib/pg_xlogdump/rmgrdesc.c
@@ -27,8 +27,8 @@
#include "storage/standby.h"
#include "utils/relmapper.h"
-#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \
- { name, desc, },
+#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \
+ { name, desc, identify, },
const RmgrDescData RmgrDescTable[RM_MAX_ID + 1] = {
#include "access/rmgrlist.h"
diff --git a/contrib/pg_xlogdump/rmgrdesc.h b/contrib/pg_xlogdump/rmgrdesc.h
index d964118..da805c5 100644
--- a/contrib/pg_xlogdump/rmgrdesc.h
+++ b/contrib/pg_xlogdump/rmgrdesc.h
@@ -14,6 +14,7 @@ typedef struct RmgrDescData
{
const char *rm_name;
void (*rm_desc) (StringInfo buf, XLogRecord *record);
+ const char *(*rm_identify) (uint8 info);
} RmgrDescData;
extern const RmgrDescData RmgrDescTable[];
diff --git a/doc/src/sgml/pg_xlogdump.sgml b/doc/src/sgml/pg_xlogdump.sgml
index 1d1a2ce..bfd9eb9 100644
--- a/doc/src/sgml/pg_xlogdump.sgml
+++ b/doc/src/sgml/pg_xlogdump.sgml
@@ -180,6 +180,28 @@ PostgreSQL documentation
</varlistentry>
<varlistentry>
+ <term><option>-z</option></term>
+ <term><option>--stats</option></term>
+ <listitem>
+ <para>
+ Display summary statistics (number and size of records and
+ full-page images per rmgr) instead of individual records.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-Z</option></term>
+ <term><option>--record-stats</option></term>
+ <listitem>
+ <para>
+ Display summary statistics (number and size of records and
+ full-page images) instead of individual records.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-?</></term>
<term><option>--help</></term>
<listitem>
diff --git a/src/backend/access/rmgrdesc/clogdesc.c b/src/backend/access/rmgrdesc/clogdesc.c
index e82baa8..08f225d 100644
--- a/src/backend/access/rmgrdesc/clogdesc.c
+++ b/src/backend/access/rmgrdesc/clogdesc.c
@@ -40,3 +40,21 @@ clog_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+clog_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case CLOG_ZEROPAGE:
+ id = "ZEROPAGE";
+ break;
+ case CLOG_TRUNCATE:
+ id = "TRUNCATE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/dbasedesc.c b/src/backend/access/rmgrdesc/dbasedesc.c
index 0230716..38f3a39 100644
--- a/src/backend/access/rmgrdesc/dbasedesc.c
+++ b/src/backend/access/rmgrdesc/dbasedesc.c
@@ -42,3 +42,21 @@ dbase_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+dbase_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_DBASE_CREATE:
+ id = "CREATE";
+ break;
+ case XLOG_DBASE_DROP:
+ id = "DROP";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/gindesc.c b/src/backend/access/rmgrdesc/gindesc.c
index 12d68d7..115ad5b 100644
--- a/src/backend/access/rmgrdesc/gindesc.c
+++ b/src/backend/access/rmgrdesc/gindesc.c
@@ -187,3 +187,45 @@ gin_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+gin_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_GIN_CREATE_INDEX:
+ id = "CREATE_INDEX";
+ break;
+ case XLOG_GIN_CREATE_PTREE:
+ id = "CREATE_PTREE";
+ break;
+ case XLOG_GIN_INSERT:
+ id = "INSERT";
+ break;
+ case XLOG_GIN_SPLIT:
+ id = "SPLIT";
+ break;
+ case XLOG_GIN_VACUUM_PAGE:
+ id = "VACUUM_PAGE";
+ break;
+ case XLOG_GIN_VACUUM_DATA_LEAF_PAGE:
+ id = "VACUUM_DATA_LEAF_PAGE";
+ break;
+ case XLOG_GIN_DELETE_PAGE:
+ id = "DELETE_PAGE";
+ break;
+ case XLOG_GIN_UPDATE_META_PAGE:
+ id = "UPDATE_META_PAGE";
+ break;
+ case XLOG_GIN_INSERT_LISTPAGE:
+ id = "INSERT_LISTPAGE";
+ break;
+ case XLOG_GIN_DELETE_LISTPAGE:
+ id = "DELETE_LISTPAGE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/gistdesc.c b/src/backend/access/rmgrdesc/gistdesc.c
index cdac496..e4f288b 100644
--- a/src/backend/access/rmgrdesc/gistdesc.c
+++ b/src/backend/access/rmgrdesc/gistdesc.c
@@ -67,3 +67,24 @@ gist_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+gist_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_GIST_PAGE_UPDATE:
+ id = "PAGE_UPDATE";
+ break;
+ case XLOG_GIST_PAGE_SPLIT:
+ id = "PAGE_SPLIT";
+ break;
+ case XLOG_GIST_CREATE_INDEX:
+ id = "CREATE_INDEX";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/hashdesc.c b/src/backend/access/rmgrdesc/hashdesc.c
index 86a0376..c58461c 100644
--- a/src/backend/access/rmgrdesc/hashdesc.c
+++ b/src/backend/access/rmgrdesc/hashdesc.c
@@ -20,3 +20,9 @@ void
hash_desc(StringInfo buf, XLogRecord *record)
{
}
+
+const char *
+hash_identify(uint8 info)
+{
+ return NULL;
+}
diff --git a/src/backend/access/rmgrdesc/heapdesc.c b/src/backend/access/rmgrdesc/heapdesc.c
index 24b6f92..91a8e72 100644
--- a/src/backend/access/rmgrdesc/heapdesc.c
+++ b/src/backend/access/rmgrdesc/heapdesc.c
@@ -193,3 +193,86 @@ heap2_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+static const char *
+append_init(const char *str)
+{
+ static char x[32];
+
+ strcpy(x, str);
+ strcat(x, "+INIT");
+
+ return x;
+}
+
+const char *
+heap_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info & XLOG_HEAP_OPMASK)
+ {
+ case XLOG_HEAP_INSERT:
+ id = "INSERT";
+ break;
+ case XLOG_HEAP_DELETE:
+ id = "DELETE";
+ break;
+ case XLOG_HEAP_UPDATE:
+ id = "UPDATE";
+ break;
+ case XLOG_HEAP_HOT_UPDATE:
+ id = "HOT_UPDATE";
+ break;
+ case XLOG_HEAP_LOCK:
+ id = "LOCK";
+ break;
+ case XLOG_HEAP_INPLACE:
+ id = "INPLACE";
+ break;
+ }
+
+ if (info & XLOG_HEAP_INIT_PAGE)
+ id = append_init(id);
+
+ return id;
+}
+
+const char *
+heap2_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info & XLOG_HEAP_OPMASK)
+ {
+ case XLOG_HEAP2_CLEAN:
+ id = "CLEAN";
+ break;
+ case XLOG_HEAP2_FREEZE_PAGE:
+ id = "FREEZE_PAGE";
+ break;
+ case XLOG_HEAP2_CLEANUP_INFO:
+ id = "CLEANUP_INFO";
+ break;
+ case XLOG_HEAP2_VISIBLE:
+ id = "VISIBLE";
+ break;
+ case XLOG_HEAP2_MULTI_INSERT:
+ id = "MULTI_INSERT";
+ break;
+ case XLOG_HEAP2_LOCK_UPDATED:
+ id = "LOCK_UPDATED";
+ break;
+ case XLOG_HEAP2_NEW_CID:
+ id = "NEW_CID";
+ break;
+ case XLOG_HEAP2_REWRITE:
+ id = "REWRITE";
+ break;
+ }
+
+ if (info & XLOG_HEAP_INIT_PAGE)
+ id = append_init(id);
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/mxactdesc.c b/src/backend/access/rmgrdesc/mxactdesc.c
index 50d9b55..d77b1c8 100644
--- a/src/backend/access/rmgrdesc/mxactdesc.c
+++ b/src/backend/access/rmgrdesc/mxactdesc.c
@@ -79,3 +79,24 @@ multixact_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+multixact_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_MULTIXACT_ZERO_OFF_PAGE:
+ id = "ZERO_OFF_PAGE";
+ break;
+ case XLOG_MULTIXACT_ZERO_MEM_PAGE:
+ id = "ZERO_MEM_PAGE";
+ break;
+ case XLOG_MULTIXACT_CREATE_ID:
+ id = "CREATE_ID";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/nbtdesc.c b/src/backend/access/rmgrdesc/nbtdesc.c
index bf3389c..821715c 100644
--- a/src/backend/access/rmgrdesc/nbtdesc.c
+++ b/src/backend/access/rmgrdesc/nbtdesc.c
@@ -172,3 +172,57 @@ btree_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+btree_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_BTREE_INSERT_LEAF:
+ id = "INSERT_LEAF";
+ break;
+ case XLOG_BTREE_INSERT_UPPER:
+ id = "INSERT_UPPER";
+ break;
+ case XLOG_BTREE_INSERT_META:
+ id = "INSERT_META";
+ break;
+ case XLOG_BTREE_SPLIT_L:
+ id = "SPLIT_L";
+ break;
+ case XLOG_BTREE_SPLIT_R:
+ id = "SPLIT_R";
+ break;
+ case XLOG_BTREE_SPLIT_L_ROOT:
+ id = "SPLIT_L_ROOT";
+ break;
+ case XLOG_BTREE_SPLIT_R_ROOT:
+ id = "SPLIT_R_ROOT";
+ break;
+ case XLOG_BTREE_VACUUM:
+ id = "VACUUM";
+ break;
+ case XLOG_BTREE_DELETE:
+ id = "DELETE";
+ break;
+ case XLOG_BTREE_MARK_PAGE_HALFDEAD:
+ id = "MARK_PAGE_HALFDEAD";
+ break;
+ case XLOG_BTREE_UNLINK_PAGE:
+ id = "UNLINK_PAGE";
+ break;
+ case XLOG_BTREE_UNLINK_PAGE_META:
+ id = "UNLINK_PAGE_META";
+ break;
+ case XLOG_BTREE_NEWROOT:
+ id = "NEWROOT";
+ break;
+ case XLOG_BTREE_REUSE_PAGE:
+ id = "REUSE_PAGE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/relmapdesc.c b/src/backend/access/rmgrdesc/relmapdesc.c
index 06fd4b3..2aebf22 100644
--- a/src/backend/access/rmgrdesc/relmapdesc.c
+++ b/src/backend/access/rmgrdesc/relmapdesc.c
@@ -32,3 +32,18 @@ relmap_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+relmap_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_RELMAP_UPDATE:
+ id = "UPDATE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/seqdesc.c b/src/backend/access/rmgrdesc/seqdesc.c
index 42eb9b9..157c7c6 100644
--- a/src/backend/access/rmgrdesc/seqdesc.c
+++ b/src/backend/access/rmgrdesc/seqdesc.c
@@ -35,3 +35,18 @@ seq_desc(StringInfo buf, XLogRecord *record)
appendStringInfo(buf, "rel %u/%u/%u",
xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
}
+
+const char *
+seq_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_SEQ_LOG:
+ id = "LOG";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/smgrdesc.c b/src/backend/access/rmgrdesc/smgrdesc.c
index c76c815..0a7a6e2 100644
--- a/src/backend/access/rmgrdesc/smgrdesc.c
+++ b/src/backend/access/rmgrdesc/smgrdesc.c
@@ -44,3 +44,21 @@ smgr_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+smgr_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_SMGR_CREATE:
+ id = "CREATE";
+ break;
+ case XLOG_SMGR_TRUNCATE:
+ id = "TRUNCATE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/spgdesc.c b/src/backend/access/rmgrdesc/spgdesc.c
index ed369b2..76f43ff 100644
--- a/src/backend/access/rmgrdesc/spgdesc.c
+++ b/src/backend/access/rmgrdesc/spgdesc.c
@@ -88,3 +88,42 @@ spg_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+spg_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_SPGIST_CREATE_INDEX:
+ id = "CREATE_INDEX";
+ break;
+ case XLOG_SPGIST_ADD_LEAF:
+ id = "ADD_LEAF";
+ break;
+ case XLOG_SPGIST_MOVE_LEAFS:
+ id = "MOVE_LEAFS";
+ break;
+ case XLOG_SPGIST_ADD_NODE:
+ id = "ADD_NODE";
+ break;
+ case XLOG_SPGIST_SPLIT_TUPLE:
+ id = "SPLIT_TUPLE";
+ break;
+ case XLOG_SPGIST_PICKSPLIT:
+ id = "PICKSPLIT";
+ break;
+ case XLOG_SPGIST_VACUUM_LEAF:
+ id = "VACUUM_LEAF";
+ break;
+ case XLOG_SPGIST_VACUUM_ROOT:
+ id = "VACUUM_ROOT";
+ break;
+ case XLOG_SPGIST_VACUUM_REDIRECT:
+ id = "VACUUM_REDIRECT";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/standbydesc.c b/src/backend/access/rmgrdesc/standbydesc.c
index a127d38..77503d4 100644
--- a/src/backend/access/rmgrdesc/standbydesc.c
+++ b/src/backend/access/rmgrdesc/standbydesc.c
@@ -64,3 +64,21 @@ standby_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+standby_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_STANDBY_LOCK:
+ id = "LOCK";
+ break;
+ case XLOG_RUNNING_XACTS:
+ id = "RUNNING_XACTS";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/tblspcdesc.c b/src/backend/access/rmgrdesc/tblspcdesc.c
index 30b1f06..c947845 100644
--- a/src/backend/access/rmgrdesc/tblspcdesc.c
+++ b/src/backend/access/rmgrdesc/tblspcdesc.c
@@ -39,3 +39,21 @@ tblspc_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+tblspc_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_TBLSPC_CREATE:
+ id = "CREATE";
+ break;
+ case XLOG_TBLSPC_DROP:
+ id = "DROP";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/xactdesc.c b/src/backend/access/rmgrdesc/xactdesc.c
index 994931e..8ea10c9 100644
--- a/src/backend/access/rmgrdesc/xactdesc.c
+++ b/src/backend/access/rmgrdesc/xactdesc.c
@@ -196,3 +196,36 @@ xact_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+xact_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_XACT_COMMIT:
+ id = "COMMIT";
+ break;
+ case XLOG_XACT_PREPARE:
+ id = "PREPARE";
+ break;
+ case XLOG_XACT_ABORT:
+ id = "ABORT";
+ break;
+ case XLOG_XACT_COMMIT_PREPARED:
+ id = "COMMIT_PREPARED";
+ break;
+ case XLOG_XACT_ABORT_PREPARED:
+ id = "ABORT_PREPARED";
+ break;
+ case XLOG_XACT_ASSIGNMENT:
+ id = "ASSIGNMENT";
+ break;
+ case XLOG_XACT_COMMIT_COMPACT:
+ id = "COMMIT_COMPACT";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/xlogdesc.c b/src/backend/access/rmgrdesc/xlogdesc.c
index 2224da1..04a1f24 100644
--- a/src/backend/access/rmgrdesc/xlogdesc.c
+++ b/src/backend/access/rmgrdesc/xlogdesc.c
@@ -144,3 +144,48 @@ xlog_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+xlog_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_CHECKPOINT_SHUTDOWN:
+ id = "CHECKPOINT_SHUTDOWN";
+ break;
+ case XLOG_CHECKPOINT_ONLINE:
+ id = "CHECKPOINT_ONLINE";
+ break;
+ case XLOG_NOOP:
+ id = "NOOP";
+ break;
+ case XLOG_NEXTOID:
+ id = "NEXTOID";
+ break;
+ case XLOG_SWITCH:
+ id = "SWITCH";
+ break;
+ case XLOG_BACKUP_END:
+ id = "BACKUP_END";
+ break;
+ case XLOG_PARAMETER_CHANGE:
+ id = "PARAMETER_CHANGE";
+ break;
+ case XLOG_RESTORE_POINT:
+ id = "RESTORE_POINT";
+ break;
+ case XLOG_FPW_CHANGE:
+ id = "FPW_CHANGE";
+ break;
+ case XLOG_END_OF_RECOVERY:
+ id = "END_OF_RECOVERY";
+ break;
+ case XLOG_FPI:
+ id = "FPI";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/transam/rmgr.c b/src/backend/access/transam/rmgr.c
index c0a7a6f..2645a7a 100644
--- a/src/backend/access/transam/rmgr.c
+++ b/src/backend/access/transam/rmgr.c
@@ -25,8 +25,8 @@
#include "utils/relmapper.h"
/* must be kept in sync with RmgrData definition in xlog_internal.h */
-#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \
- { name, redo, desc, startup, cleanup },
+#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \
+ { name, redo, desc, identify, startup, cleanup },
const RmgrData RmgrTable[RM_MAX_ID + 1] = {
#include "access/rmgrlist.h"
diff --git a/src/include/access/clog.h b/src/include/access/clog.h
index be9b867..8562631 100644
--- a/src/include/access/clog.h
+++ b/src/include/access/clog.h
@@ -49,5 +49,6 @@ extern void TruncateCLOG(TransactionId oldestXact);
extern void clog_redo(XLogRecPtr lsn, XLogRecord *record);
extern void clog_desc(StringInfo buf, XLogRecord *record);
+extern const char *clog_identify(uint8 info);
#endif /* CLOG_H */
diff --git a/src/include/access/gin.h b/src/include/access/gin.h
index a0b288d..0ebecb4 100644
--- a/src/include/access/gin.h
+++ b/src/include/access/gin.h
@@ -74,6 +74,7 @@ extern void ginUpdateStats(Relation index, const GinStatsData *stats);
/* ginxlog.c */
extern void gin_redo(XLogRecPtr lsn, XLogRecord *record);
extern void gin_desc(StringInfo buf, XLogRecord *record);
+extern const char *gin_identify(uint8 info);
extern void gin_xlog_startup(void);
extern void gin_xlog_cleanup(void);
diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h
index 03e9903..879f113 100644
--- a/src/include/access/gist_private.h
+++ b/src/include/access/gist_private.h
@@ -452,6 +452,7 @@ extern SplitedPageLayout *gistSplit(Relation r, Page page, IndexTuple *itup,
/* gistxlog.c */
extern void gist_redo(XLogRecPtr lsn, XLogRecord *record);
extern void gist_desc(StringInfo buf, XLogRecord *record);
+extern const char *gist_identify(uint8 info);
extern void gist_xlog_startup(void);
extern void gist_xlog_cleanup(void);
diff --git a/src/include/access/hash.h b/src/include/access/hash.h
index ff29fea..a81b9de 100644
--- a/src/include/access/hash.h
+++ b/src/include/access/hash.h
@@ -357,5 +357,6 @@ extern OffsetNumber _hash_binsearch_last(Page page, uint32 hash_value);
/* hash.c */
extern void hash_redo(XLogRecPtr lsn, XLogRecord *record);
extern void hash_desc(StringInfo buf, XLogRecord *record);
+extern const char *hash_identify(uint8 info);
#endif /* HASH_H */
diff --git a/src/include/access/heapam_xlog.h b/src/include/access/heapam_xlog.h
index 2544347..5ac98a5 100644
--- a/src/include/access/heapam_xlog.h
+++ b/src/include/access/heapam_xlog.h
@@ -357,8 +357,10 @@ extern void HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple,
extern void heap_redo(XLogRecPtr lsn, XLogRecord *record);
extern void heap_desc(StringInfo buf, XLogRecord *record);
+extern const char *heap_identify(uint8 info);
extern void heap2_redo(XLogRecPtr lsn, XLogRecord *record);
extern void heap2_desc(StringInfo buf, XLogRecord *record);
+extern const char *heap2_identify(uint8 info);
extern void heap_xlog_logical_rewrite(XLogRecPtr lsn, XLogRecord *r);
extern XLogRecPtr log_heap_cleanup_info(RelFileNode rnode,
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index 8db773b..b331447 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -136,6 +136,7 @@ extern void multixact_twophase_postabort(TransactionId xid, uint16 info,
extern void multixact_redo(XLogRecPtr lsn, XLogRecord *record);
extern void multixact_desc(StringInfo buf, XLogRecord *record);
+extern const char *multixact_identify(uint8 info);
extern char *mxid_to_string(MultiXactId multi, int nmembers,
MultiXactMember *members);
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
index 9fa943f..90fd6d0 100644
--- a/src/include/access/nbtree.h
+++ b/src/include/access/nbtree.h
@@ -726,5 +726,6 @@ extern void _bt_leafbuild(BTSpool *btspool, BTSpool *spool2);
*/
extern void btree_redo(XLogRecPtr lsn, XLogRecord *record);
extern void btree_desc(StringInfo buf, XLogRecord *record);
+extern const char *btree_identify(uint8 info);
#endif /* NBTREE_H */
diff --git a/src/include/access/rmgr.h b/src/include/access/rmgr.h
index 1b577a2..ff7fe62 100644
--- a/src/include/access/rmgr.h
+++ b/src/include/access/rmgr.h
@@ -19,7 +19,7 @@ typedef uint8 RmgrId;
* Note: RM_MAX_ID must fit in RmgrId; widening that type will affect the XLOG
* file format.
*/
-#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \
+#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \
symname,
typedef enum RmgrIds
diff --git a/src/include/access/rmgrlist.h b/src/include/access/rmgrlist.h
index 662fb77..77d4574 100644
--- a/src/include/access/rmgrlist.h
+++ b/src/include/access/rmgrlist.h
@@ -25,20 +25,20 @@
*/
/* symbol name, textual name, redo, desc, startup, cleanup */
-PG_RMGR(RM_XLOG_ID, "XLOG", xlog_redo, xlog_desc, NULL, NULL)
-PG_RMGR(RM_XACT_ID, "Transaction", xact_redo, xact_desc, NULL, NULL)
-PG_RMGR(RM_SMGR_ID, "Storage", smgr_redo, smgr_desc, NULL, NULL)
-PG_RMGR(RM_CLOG_ID, "CLOG", clog_redo, clog_desc, NULL, NULL)
-PG_RMGR(RM_DBASE_ID, "Database", dbase_redo, dbase_desc, NULL, NULL)
-PG_RMGR(RM_TBLSPC_ID, "Tablespace", tblspc_redo, tblspc_desc, NULL, NULL)
-PG_RMGR(RM_MULTIXACT_ID, "MultiXact", multixact_redo, multixact_desc, NULL, NULL)
-PG_RMGR(RM_RELMAP_ID, "RelMap", relmap_redo, relmap_desc, NULL, NULL)
-PG_RMGR(RM_STANDBY_ID, "Standby", standby_redo, standby_desc, NULL, NULL)
-PG_RMGR(RM_HEAP2_ID, "Heap2", heap2_redo, heap2_desc, NULL, NULL)
-PG_RMGR(RM_HEAP_ID, "Heap", heap_redo, heap_desc, NULL, NULL)
-PG_RMGR(RM_BTREE_ID, "Btree", btree_redo, btree_desc, NULL, NULL)
-PG_RMGR(RM_HASH_ID, "Hash", hash_redo, hash_desc, NULL, NULL)
-PG_RMGR(RM_GIN_ID, "Gin", gin_redo, gin_desc, gin_xlog_startup, gin_xlog_cleanup)
-PG_RMGR(RM_GIST_ID, "Gist", gist_redo, gist_desc, gist_xlog_startup, gist_xlog_cleanup)
-PG_RMGR(RM_SEQ_ID, "Sequence", seq_redo, seq_desc, NULL, NULL)
-PG_RMGR(RM_SPGIST_ID, "SPGist", spg_redo, spg_desc, spg_xlog_startup, spg_xlog_cleanup)
+PG_RMGR(RM_XLOG_ID, "XLOG", xlog_redo, xlog_desc, xlog_identify, NULL, NULL)
+PG_RMGR(RM_XACT_ID, "Transaction", xact_redo, xact_desc, xact_identify, NULL, NULL)
+PG_RMGR(RM_SMGR_ID, "Storage", smgr_redo, smgr_desc, smgr_identify, NULL, NULL)
+PG_RMGR(RM_CLOG_ID, "CLOG", clog_redo, clog_desc, clog_identify, NULL, NULL)
+PG_RMGR(RM_DBASE_ID, "Database", dbase_redo, dbase_desc, dbase_identify, NULL, NULL)
+PG_RMGR(RM_TBLSPC_ID, "Tablespace", tblspc_redo, tblspc_desc, tblspc_identify, NULL, NULL)
+PG_RMGR(RM_MULTIXACT_ID, "MultiXact", multixact_redo, multixact_desc, multixact_identify, NULL, NULL)
+PG_RMGR(RM_RELMAP_ID, "RelMap", relmap_redo, relmap_desc, relmap_identify, NULL, NULL)
+PG_RMGR(RM_STANDBY_ID, "Standby", standby_redo, standby_desc, standby_identify, NULL, NULL)
+PG_RMGR(RM_HEAP2_ID, "Heap2", heap2_redo, heap2_desc, heap2_identify, NULL, NULL)
+PG_RMGR(RM_HEAP_ID, "Heap", heap_redo, heap_desc, heap_identify, NULL, NULL)
+PG_RMGR(RM_BTREE_ID, "Btree", btree_redo, btree_desc, btree_identify, NULL, NULL)
+PG_RMGR(RM_HASH_ID, "Hash", hash_redo, hash_desc, hash_identify, NULL, NULL)
+PG_RMGR(RM_GIN_ID, "Gin", gin_redo, gin_desc, gin_identify, gin_xlog_startup, gin_xlog_cleanup)
+PG_RMGR(RM_GIST_ID, "Gist", gist_redo, gist_desc, gist_identify, gist_xlog_startup, gist_xlog_cleanup)
+PG_RMGR(RM_SEQ_ID, "Sequence", seq_redo, seq_desc, seq_identify, NULL, NULL)
+PG_RMGR(RM_SPGIST_ID, "SPGist", spg_redo, spg_desc, spg_identify, spg_xlog_startup, spg_xlog_cleanup)
diff --git a/src/include/access/spgist.h b/src/include/access/spgist.h
index 7f8655c..f218a83 100644
--- a/src/include/access/spgist.h
+++ b/src/include/access/spgist.h
@@ -198,6 +198,7 @@ extern Datum spgvacuumcleanup(PG_FUNCTION_ARGS);
/* spgxlog.c */
extern void spg_redo(XLogRecPtr lsn, XLogRecord *record);
extern void spg_desc(StringInfo buf, XLogRecord *record);
+extern const char *spg_identify(uint8 info);
extern void spg_xlog_startup(void);
extern void spg_xlog_cleanup(void);
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 2168dc3..45376b4 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -256,5 +256,6 @@ extern int xactGetCommittedChildren(TransactionId **ptr);
extern void xact_redo(XLogRecPtr lsn, XLogRecord *record);
extern void xact_desc(StringInfo buf, XLogRecord *record);
+extern const char *xact_identify(uint8 info);
#endif /* XACT_H */
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 7d6db49..0b7bfa5 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -304,6 +304,7 @@ extern Buffer RestoreBackupBlock(XLogRecPtr lsn, XLogRecord *record,
extern void xlog_redo(XLogRecPtr lsn, XLogRecord *record);
extern void xlog_desc(StringInfo buf, XLogRecord *record);
+extern const char *xlog_identify(uint8 info);
extern void issue_xlog_fsync(int fd, XLogSegNo segno);
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index 954114f..d53520a 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -246,6 +246,7 @@ typedef struct RmgrData
const char *rm_name;
void (*rm_redo) (XLogRecPtr lsn, struct XLogRecord *rptr);
void (*rm_desc) (StringInfo buf, struct XLogRecord *rptr);
+ const char *(*rm_identify) (uint8 info);
void (*rm_startup) (void);
void (*rm_cleanup) (void);
} RmgrData;
diff --git a/src/include/c.h b/src/include/c.h
index 2ceaaf6..cf3cbd1 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -867,6 +867,9 @@ typedef NameData *Name;
* ----------------------------------------------------------------
*/
+#define INT64_FORMAT "%" INT64_MODIFIER "d"
+#define UINT64_FORMAT "%" INT64_MODIFIER "u"
+
/* msb for char */
#define HIGHBIT (0x80)
#define IS_HIGHBIT_SET(ch) ((unsigned char)(ch) & HIGHBIT)
diff --git a/src/include/catalog/storage_xlog.h b/src/include/catalog/storage_xlog.h
index 7081c99..5fc7235 100644
--- a/src/include/catalog/storage_xlog.h
+++ b/src/include/catalog/storage_xlog.h
@@ -45,5 +45,6 @@ extern void log_smgrcreate(RelFileNode *rnode, ForkNumber forkNum);
extern void smgr_redo(XLogRecPtr lsn, XLogRecord *record);
extern void smgr_desc(StringInfo buf, XLogRecord *record);
+extern const char *smgr_identify(uint8 info);
#endif /* STORAGE_XLOG_H */
diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h
index c2380dc..811713f 100644
--- a/src/include/commands/dbcommands.h
+++ b/src/include/commands/dbcommands.h
@@ -64,6 +64,7 @@ extern char *get_database_name(Oid dbid);
extern void dbase_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void dbase_desc(StringInfo buf, XLogRecord *rptr);
+extern const char *dbase_identify(uint8 info);
extern void check_encoding_locale_matches(int encoding, const char *collate, const char *ctype);
diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h
index 8819c00..914d155 100644
--- a/src/include/commands/sequence.h
+++ b/src/include/commands/sequence.h
@@ -78,5 +78,6 @@ extern void ResetSequenceCaches(void);
extern void seq_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void seq_desc(StringInfo buf, XLogRecord *rptr);
+extern const char *seq_identify(uint8 info);
#endif /* SEQUENCE_H */
diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h
index d01ae8b..0f16f40 100644
--- a/src/include/commands/tablespace.h
+++ b/src/include/commands/tablespace.h
@@ -57,5 +57,6 @@ extern bool directory_is_empty(const char *path);
extern void tblspc_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void tblspc_desc(StringInfo buf, XLogRecord *rptr);
+extern const char *tblspc_identify(uint8 info);
#endif /* TABLESPACE_H */
diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h
index da22fd3..1c63af5 100644
--- a/src/include/storage/standby.h
+++ b/src/include/storage/standby.h
@@ -83,6 +83,7 @@ typedef struct xl_running_xacts
/* Recovery handlers for the Standby Rmgr (RM_STANDBY_ID) */
extern void standby_redo(XLogRecPtr lsn, XLogRecord *record);
extern void standby_desc(StringInfo buf, XLogRecord *record);
+extern const char *standby_identify(uint8 info);
/*
* Declarations for GetRunningTransactionData(). Similar to Snapshots, but
diff --git a/src/include/utils/relmapper.h b/src/include/utils/relmapper.h
index 76bcf18..37937dd 100644
--- a/src/include/utils/relmapper.h
+++ b/src/include/utils/relmapper.h
@@ -60,5 +60,6 @@ extern void RelationMapInitializePhase3(void);
extern void relmap_redo(XLogRecPtr lsn, XLogRecord *record);
extern void relmap_desc(StringInfo buf, XLogRecord *record);
+extern const char *relmap_identify(uint8 info);
#endif /* RELMAPPER_H */
--
1.9.1
0002-Clearly-separate-rm_identify-and-rm_desc-outputs.patchtext/x-diff; charset=us-asciiDownload
>From ba1e4848383fb277fb1aca48f9253abc69a6af9d Mon Sep 17 00:00:00 2001
From: Abhijit Menon-Sen <ams@2ndQuadrant.com>
Date: Fri, 19 Sep 2014 13:14:26 +0530
Subject: Clearly separate rm_identify and rm_desc outputs
rm_identify returns NULL or a name based on the #define corresponding to
xl_info. rm_desc adds additional detail if there is any to be had. Now
we can just glue the output together in xlog.c.
---
src/backend/access/rmgrdesc/clogdesc.c | 13 +-----
src/backend/access/rmgrdesc/dbasedesc.c | 6 +--
src/backend/access/rmgrdesc/gindesc.c | 14 +-----
src/backend/access/rmgrdesc/gistdesc.c | 6 +--
src/backend/access/rmgrdesc/heapdesc.c | 40 +++--------------
src/backend/access/rmgrdesc/mxactdesc.c | 16 ++-----
src/backend/access/rmgrdesc/nbtdesc.c | 72 +++++--------------------------
src/backend/access/rmgrdesc/relmapdesc.c | 4 +-
src/backend/access/rmgrdesc/seqdesc.c | 12 ++----
src/backend/access/rmgrdesc/smgrdesc.c | 7 +--
src/backend/access/rmgrdesc/spgdesc.c | 22 ++++------
src/backend/access/rmgrdesc/standbydesc.c | 7 +--
src/backend/access/rmgrdesc/tblspcdesc.c | 7 +--
src/backend/access/rmgrdesc/xactdesc.c | 15 ++-----
src/backend/access/rmgrdesc/xlogdesc.c | 27 ++++--------
src/backend/access/transam/xlog.c | 36 ++++++++++++++--
src/include/access/xlog_internal.h | 6 +++
17 files changed, 94 insertions(+), 216 deletions(-)
diff --git a/src/backend/access/rmgrdesc/clogdesc.c b/src/backend/access/rmgrdesc/clogdesc.c
index 08f225d..8beb6d0 100644
--- a/src/backend/access/rmgrdesc/clogdesc.c
+++ b/src/backend/access/rmgrdesc/clogdesc.c
@@ -23,22 +23,13 @@ clog_desc(StringInfo buf, XLogRecord *record)
char *rec = XLogRecGetData(record);
uint8 info = record->xl_info & ~XLR_INFO_MASK;
- if (info == CLOG_ZEROPAGE)
+ if (info == CLOG_ZEROPAGE || info == CLOG_TRUNCATE)
{
int pageno;
memcpy(&pageno, rec, sizeof(int));
- appendStringInfo(buf, "zeropage: %d", pageno);
+ appendStringInfo(buf, "%d", pageno);
}
- else if (info == CLOG_TRUNCATE)
- {
- int pageno;
-
- memcpy(&pageno, rec, sizeof(int));
- appendStringInfo(buf, "truncate before: %d", pageno);
- }
- else
- appendStringInfoString(buf, "UNKNOWN");
}
const char *
diff --git a/src/backend/access/rmgrdesc/dbasedesc.c b/src/backend/access/rmgrdesc/dbasedesc.c
index 38f3a39..e36988a 100644
--- a/src/backend/access/rmgrdesc/dbasedesc.c
+++ b/src/backend/access/rmgrdesc/dbasedesc.c
@@ -28,7 +28,7 @@ dbase_desc(StringInfo buf, XLogRecord *record)
{
xl_dbase_create_rec *xlrec = (xl_dbase_create_rec *) rec;
- appendStringInfo(buf, "create db: copy dir %u/%u to %u/%u",
+ appendStringInfo(buf, "copy dir %u/%u to %u/%u",
xlrec->src_db_id, xlrec->src_tablespace_id,
xlrec->db_id, xlrec->tablespace_id);
}
@@ -36,11 +36,9 @@ dbase_desc(StringInfo buf, XLogRecord *record)
{
xl_dbase_drop_rec *xlrec = (xl_dbase_drop_rec *) rec;
- appendStringInfo(buf, "drop db: dir %u/%u",
+ appendStringInfo(buf, "dir %u/%u",
xlrec->db_id, xlrec->tablespace_id);
}
- else
- appendStringInfoString(buf, "UNKNOWN");
}
const char *
diff --git a/src/backend/access/rmgrdesc/gindesc.c b/src/backend/access/rmgrdesc/gindesc.c
index 115ad5b..dd4c791 100644
--- a/src/backend/access/rmgrdesc/gindesc.c
+++ b/src/backend/access/rmgrdesc/gindesc.c
@@ -85,11 +85,9 @@ gin_desc(StringInfo buf, XLogRecord *record)
switch (info)
{
case XLOG_GIN_CREATE_INDEX:
- appendStringInfoString(buf, "Create index, ");
desc_node(buf, *(RelFileNode *) rec, GIN_ROOT_BLKNO);
break;
case XLOG_GIN_CREATE_PTREE:
- appendStringInfoString(buf, "Create posting tree, ");
desc_node(buf, ((ginxlogCreatePostingTree *) rec)->node, ((ginxlogCreatePostingTree *) rec)->blkno);
break;
case XLOG_GIN_INSERT:
@@ -97,7 +95,6 @@ gin_desc(StringInfo buf, XLogRecord *record)
ginxlogInsert *xlrec = (ginxlogInsert *) rec;
char *payload = rec + sizeof(ginxlogInsert);
- appendStringInfoString(buf, "Insert item, ");
desc_node(buf, xlrec->node, xlrec->blkno);
appendStringInfo(buf, " isdata: %c isleaf: %c",
(xlrec->flags & GIN_INSERT_ISDATA) ? 'T' : 'F',
@@ -142,7 +139,6 @@ gin_desc(StringInfo buf, XLogRecord *record)
{
ginxlogSplit *xlrec = (ginxlogSplit *) rec;
- appendStringInfoString(buf, "Page split, ");
desc_node(buf, ((ginxlogSplit *) rec)->node, ((ginxlogSplit *) rec)->lblkno);
appendStringInfo(buf, " isrootsplit: %c", (((ginxlogSplit *) rec)->flags & GIN_SPLIT_ROOT) ? 'T' : 'F');
appendStringInfo(buf, " isdata: %c isleaf: %c",
@@ -151,14 +147,12 @@ gin_desc(StringInfo buf, XLogRecord *record)
}
break;
case XLOG_GIN_VACUUM_PAGE:
- appendStringInfoString(buf, "Vacuum page, ");
desc_node(buf, ((ginxlogVacuumPage *) rec)->node, ((ginxlogVacuumPage *) rec)->blkno);
break;
case XLOG_GIN_VACUUM_DATA_LEAF_PAGE:
{
ginxlogVacuumDataLeafPage *xlrec = (ginxlogVacuumDataLeafPage *) rec;
- appendStringInfoString(buf, "Vacuum data leaf page, ");
desc_node(buf, xlrec->node, xlrec->blkno);
if (record->xl_info & XLR_BKP_BLOCK(0))
appendStringInfo(buf, " (full page image)");
@@ -167,24 +161,18 @@ gin_desc(StringInfo buf, XLogRecord *record)
}
break;
case XLOG_GIN_DELETE_PAGE:
- appendStringInfoString(buf, "Delete page, ");
desc_node(buf, ((ginxlogDeletePage *) rec)->node, ((ginxlogDeletePage *) rec)->blkno);
break;
case XLOG_GIN_UPDATE_META_PAGE:
- appendStringInfoString(buf, "Update metapage, ");
desc_node(buf, ((ginxlogUpdateMeta *) rec)->node, GIN_METAPAGE_BLKNO);
break;
case XLOG_GIN_INSERT_LISTPAGE:
- appendStringInfoString(buf, "Insert new list page, ");
desc_node(buf, ((ginxlogInsertListPage *) rec)->node, ((ginxlogInsertListPage *) rec)->blkno);
break;
case XLOG_GIN_DELETE_LISTPAGE:
- appendStringInfo(buf, "Delete list pages (%d), ", ((ginxlogDeleteListPages *) rec)->ndeleted);
+ appendStringInfo(buf, "%d pages, ", ((ginxlogDeleteListPages *) rec)->ndeleted);
desc_node(buf, ((ginxlogDeleteListPages *) rec)->node, GIN_METAPAGE_BLKNO);
break;
- default:
- appendStringInfo(buf, "unknown gin op code %u", info);
- break;
}
}
diff --git a/src/backend/access/rmgrdesc/gistdesc.c b/src/backend/access/rmgrdesc/gistdesc.c
index e4f288b..f2ed1f6 100644
--- a/src/backend/access/rmgrdesc/gistdesc.c
+++ b/src/backend/access/rmgrdesc/gistdesc.c
@@ -50,21 +50,17 @@ gist_desc(StringInfo buf, XLogRecord *record)
switch (info)
{
case XLOG_GIST_PAGE_UPDATE:
- appendStringInfoString(buf, "page_update: ");
out_gistxlogPageUpdate(buf, (gistxlogPageUpdate *) rec);
break;
case XLOG_GIST_PAGE_SPLIT:
out_gistxlogPageSplit(buf, (gistxlogPageSplit *) rec);
break;
case XLOG_GIST_CREATE_INDEX:
- appendStringInfo(buf, "create_index: rel %u/%u/%u",
+ appendStringInfo(buf, "rel %u/%u/%u",
((RelFileNode *) rec)->spcNode,
((RelFileNode *) rec)->dbNode,
((RelFileNode *) rec)->relNode);
break;
- default:
- appendStringInfo(buf, "unknown gist op code %u", info);
- break;
}
}
diff --git a/src/backend/access/rmgrdesc/heapdesc.c b/src/backend/access/rmgrdesc/heapdesc.c
index 91a8e72..cd9d59d 100644
--- a/src/backend/access/rmgrdesc/heapdesc.c
+++ b/src/backend/access/rmgrdesc/heapdesc.c
@@ -51,17 +51,12 @@ heap_desc(StringInfo buf, XLogRecord *record)
{
xl_heap_insert *xlrec = (xl_heap_insert *) rec;
- if (record->xl_info & XLOG_HEAP_INIT_PAGE)
- appendStringInfoString(buf, "insert(init): ");
- else
- appendStringInfoString(buf, "insert: ");
out_target(buf, &(xlrec->target));
}
else if (info == XLOG_HEAP_DELETE)
{
xl_heap_delete *xlrec = (xl_heap_delete *) rec;
- appendStringInfoString(buf, "delete: ");
out_target(buf, &(xlrec->target));
appendStringInfoChar(buf, ' ');
out_infobits(buf, xlrec->infobits_set);
@@ -70,10 +65,6 @@ heap_desc(StringInfo buf, XLogRecord *record)
{
xl_heap_update *xlrec = (xl_heap_update *) rec;
- if (record->xl_info & XLOG_HEAP_INIT_PAGE)
- appendStringInfoString(buf, "update(init): ");
- else
- appendStringInfoString(buf, "update: ");
out_target(buf, &(xlrec->target));
appendStringInfo(buf, " xmax %u ", xlrec->old_xmax);
out_infobits(buf, xlrec->old_infobits_set);
@@ -86,10 +77,6 @@ heap_desc(StringInfo buf, XLogRecord *record)
{
xl_heap_update *xlrec = (xl_heap_update *) rec;
- if (record->xl_info & XLOG_HEAP_INIT_PAGE) /* can this case happen? */
- appendStringInfoString(buf, "hot_update(init): ");
- else
- appendStringInfoString(buf, "hot_update: ");
out_target(buf, &(xlrec->target));
appendStringInfo(buf, " xmax %u ", xlrec->old_xmax);
out_infobits(buf, xlrec->old_infobits_set);
@@ -102,7 +89,7 @@ heap_desc(StringInfo buf, XLogRecord *record)
{
xl_heap_lock *xlrec = (xl_heap_lock *) rec;
- appendStringInfo(buf, "lock %u: ", xlrec->locking_xid);
+ appendStringInfo(buf, "xid %u: ", xlrec->locking_xid);
out_target(buf, &(xlrec->target));
appendStringInfoChar(buf, ' ');
out_infobits(buf, xlrec->infobits_set);
@@ -111,11 +98,8 @@ heap_desc(StringInfo buf, XLogRecord *record)
{
xl_heap_inplace *xlrec = (xl_heap_inplace *) rec;
- appendStringInfoString(buf, "inplace: ");
out_target(buf, &(xlrec->target));
}
- else
- appendStringInfoString(buf, "UNKNOWN");
}
void
heap2_desc(StringInfo buf, XLogRecord *record)
@@ -128,7 +112,7 @@ heap2_desc(StringInfo buf, XLogRecord *record)
{
xl_heap_clean *xlrec = (xl_heap_clean *) rec;
- appendStringInfo(buf, "clean: rel %u/%u/%u; blk %u remxid %u",
+ appendStringInfo(buf, "rel %u/%u/%u; blk %u remxid %u",
xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->node.relNode, xlrec->block,
xlrec->latestRemovedXid);
@@ -137,27 +121,22 @@ heap2_desc(StringInfo buf, XLogRecord *record)
{
xl_heap_freeze_page *xlrec = (xl_heap_freeze_page *) rec;
- appendStringInfo(buf, "freeze_page: rel %u/%u/%u; blk %u; cutoff xid %u ntuples %u",
+ appendStringInfo(buf, "rel %u/%u/%u; blk %u; cutoff xid %u ntuples %u",
xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->node.relNode, xlrec->block,
xlrec->cutoff_xid, xlrec->ntuples);
}
- else if (info == XLOG_HEAP2_REWRITE)
- {
- appendStringInfoString(buf, "heap rewrite:");
- }
else if (info == XLOG_HEAP2_CLEANUP_INFO)
{
xl_heap_cleanup_info *xlrec = (xl_heap_cleanup_info *) rec;
- appendStringInfo(buf, "cleanup info: remxid %u",
- xlrec->latestRemovedXid);
+ appendStringInfo(buf, "remxid %u", xlrec->latestRemovedXid);
}
else if (info == XLOG_HEAP2_VISIBLE)
{
xl_heap_visible *xlrec = (xl_heap_visible *) rec;
- appendStringInfo(buf, "visible: rel %u/%u/%u; blk %u",
+ appendStringInfo(buf, "rel %u/%u/%u; blk %u",
xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->node.relNode, xlrec->block);
}
@@ -165,10 +144,6 @@ heap2_desc(StringInfo buf, XLogRecord *record)
{
xl_heap_multi_insert *xlrec = (xl_heap_multi_insert *) rec;
- if (record->xl_info & XLOG_HEAP_INIT_PAGE)
- appendStringInfoString(buf, "multi-insert (init): ");
- else
- appendStringInfoString(buf, "multi-insert: ");
appendStringInfo(buf, "rel %u/%u/%u; blk %u; %d tuples",
xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
xlrec->blkno, xlrec->ntuples);
@@ -177,7 +152,7 @@ heap2_desc(StringInfo buf, XLogRecord *record)
{
xl_heap_lock_updated *xlrec = (xl_heap_lock_updated *) rec;
- appendStringInfo(buf, "lock updated: xmax %u msk %04x; ", xlrec->xmax,
+ appendStringInfo(buf, "xmax %u msk %04x; ", xlrec->xmax,
xlrec->infobits_set);
out_target(buf, &(xlrec->target));
}
@@ -185,13 +160,10 @@ heap2_desc(StringInfo buf, XLogRecord *record)
{
xl_heap_new_cid *xlrec = (xl_heap_new_cid *) rec;
- appendStringInfo(buf, "new_cid: ");
out_target(buf, &(xlrec->target));
appendStringInfo(buf, "; cmin: %u, cmax: %u, combo: %u",
xlrec->cmin, xlrec->cmax, xlrec->combocid);
}
- else
- appendStringInfoString(buf, "UNKNOWN");
}
static const char *
diff --git a/src/backend/access/rmgrdesc/mxactdesc.c b/src/backend/access/rmgrdesc/mxactdesc.c
index d77b1c8..177aebe 100644
--- a/src/backend/access/rmgrdesc/mxactdesc.c
+++ b/src/backend/access/rmgrdesc/mxactdesc.c
@@ -52,32 +52,24 @@ multixact_desc(StringInfo buf, XLogRecord *record)
char *rec = XLogRecGetData(record);
uint8 info = record->xl_info & ~XLR_INFO_MASK;
- if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
+ if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE ||
+ info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
{
int pageno;
memcpy(&pageno, rec, sizeof(int));
- appendStringInfo(buf, "zero offsets page: %d", pageno);
- }
- else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
- {
- int pageno;
-
- memcpy(&pageno, rec, sizeof(int));
- appendStringInfo(buf, "zero members page: %d", pageno);
+ appendStringInfo(buf, "%d", pageno);
}
else if (info == XLOG_MULTIXACT_CREATE_ID)
{
xl_multixact_create *xlrec = (xl_multixact_create *) rec;
int i;
- appendStringInfo(buf, "create mxid %u offset %u nmembers %d: ", xlrec->mid,
+ appendStringInfo(buf, "%u offset %u nmembers %d: ", xlrec->mid,
xlrec->moff, xlrec->nmembers);
for (i = 0; i < xlrec->nmembers; i++)
out_member(buf, &xlrec->members[i]);
}
- else
- appendStringInfoString(buf, "UNKNOWN");
}
const char *
diff --git a/src/backend/access/rmgrdesc/nbtdesc.c b/src/backend/access/rmgrdesc/nbtdesc.c
index 821715c..7eb3bbd 100644
--- a/src/backend/access/rmgrdesc/nbtdesc.c
+++ b/src/backend/access/rmgrdesc/nbtdesc.c
@@ -34,74 +34,26 @@ btree_desc(StringInfo buf, XLogRecord *record)
switch (info)
{
case XLOG_BTREE_INSERT_LEAF:
- {
- xl_btree_insert *xlrec = (xl_btree_insert *) rec;
-
- appendStringInfoString(buf, "insert: ");
- out_target(buf, &(xlrec->target));
- break;
- }
case XLOG_BTREE_INSERT_UPPER:
- {
- xl_btree_insert *xlrec = (xl_btree_insert *) rec;
-
- appendStringInfoString(buf, "insert_upper: ");
- out_target(buf, &(xlrec->target));
- break;
- }
case XLOG_BTREE_INSERT_META:
{
xl_btree_insert *xlrec = (xl_btree_insert *) rec;
- appendStringInfoString(buf, "insert_meta: ");
out_target(buf, &(xlrec->target));
break;
}
case XLOG_BTREE_SPLIT_L:
- {
- xl_btree_split *xlrec = (xl_btree_split *) rec;
-
- appendStringInfo(buf, "split_l: rel %u/%u/%u ",
- xlrec->node.spcNode, xlrec->node.dbNode,
- xlrec->node.relNode);
- appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
- xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
- xlrec->level, xlrec->firstright);
- break;
- }
case XLOG_BTREE_SPLIT_R:
- {
- xl_btree_split *xlrec = (xl_btree_split *) rec;
-
- appendStringInfo(buf, "split_r: rel %u/%u/%u ",
- xlrec->node.spcNode, xlrec->node.dbNode,
- xlrec->node.relNode);
- appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
- xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
- xlrec->level, xlrec->firstright);
- break;
- }
case XLOG_BTREE_SPLIT_L_ROOT:
- {
- xl_btree_split *xlrec = (xl_btree_split *) rec;
-
- appendStringInfo(buf, "split_l_root: rel %u/%u/%u ",
- xlrec->node.spcNode, xlrec->node.dbNode,
- xlrec->node.relNode);
- appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
- xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
- xlrec->level, xlrec->firstright);
- break;
- }
case XLOG_BTREE_SPLIT_R_ROOT:
{
xl_btree_split *xlrec = (xl_btree_split *) rec;
- appendStringInfo(buf, "split_r_root: rel %u/%u/%u ",
+ appendStringInfo(buf, "rel %u/%u/%u ",
xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->node.relNode);
appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
- xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
+ xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
xlrec->level, xlrec->firstright);
break;
}
@@ -109,7 +61,7 @@ btree_desc(StringInfo buf, XLogRecord *record)
{
xl_btree_vacuum *xlrec = (xl_btree_vacuum *) rec;
- appendStringInfo(buf, "vacuum: rel %u/%u/%u; blk %u, lastBlockVacuumed %u",
+ appendStringInfo(buf, "rel %u/%u/%u; blk %u, lastBlockVacuumed %u",
xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->node.relNode, xlrec->block,
xlrec->lastBlockVacuumed);
@@ -119,8 +71,8 @@ btree_desc(StringInfo buf, XLogRecord *record)
{
xl_btree_delete *xlrec = (xl_btree_delete *) rec;
- appendStringInfo(buf, "delete: index %u/%u/%u; iblk %u, heap %u/%u/%u;",
- xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
+ appendStringInfo(buf, "index %u/%u/%u; iblk %u, heap %u/%u/%u;",
+ xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
xlrec->block,
xlrec->hnode.spcNode, xlrec->hnode.dbNode, xlrec->hnode.relNode);
break;
@@ -129,7 +81,6 @@ btree_desc(StringInfo buf, XLogRecord *record)
{
xl_btree_mark_page_halfdead *xlrec = (xl_btree_mark_page_halfdead *) rec;
- appendStringInfoString(buf, "mark_page_halfdead: ");
out_target(buf, &(xlrec->target));
appendStringInfo(buf, "; topparent %u; leaf %u; left %u; right %u",
xlrec->topparent, xlrec->leafblk, xlrec->leftblk, xlrec->rightblk);
@@ -140,8 +91,8 @@ btree_desc(StringInfo buf, XLogRecord *record)
{
xl_btree_unlink_page *xlrec = (xl_btree_unlink_page *) rec;
- appendStringInfo(buf, "unlink_page: rel %u/%u/%u; ",
- xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
+ appendStringInfo(buf, "rel %u/%u/%u; ",
+ xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
appendStringInfo(buf, "dead %u; left %u; right %u; btpo_xact %u; ",
xlrec->deadblk, xlrec->leftsib, xlrec->rightsib, xlrec->btpo_xact);
appendStringInfo(buf, "leaf %u; leafleft %u; leafright %u; topparent %u",
@@ -152,7 +103,7 @@ btree_desc(StringInfo buf, XLogRecord *record)
{
xl_btree_newroot *xlrec = (xl_btree_newroot *) rec;
- appendStringInfo(buf, "newroot: rel %u/%u/%u; root %u lev %u",
+ appendStringInfo(buf, "rel %u/%u/%u; root %u lev %u",
xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->node.relNode,
xlrec->rootblk, xlrec->level);
@@ -162,14 +113,11 @@ btree_desc(StringInfo buf, XLogRecord *record)
{
xl_btree_reuse_page *xlrec = (xl_btree_reuse_page *) rec;
- appendStringInfo(buf, "reuse_page: rel %u/%u/%u; latestRemovedXid %u",
+ appendStringInfo(buf, "rel %u/%u/%u; latestRemovedXid %u",
xlrec->node.spcNode, xlrec->node.dbNode,
- xlrec->node.relNode, xlrec->latestRemovedXid);
+ xlrec->node.relNode, xlrec->latestRemovedXid);
break;
}
- default:
- appendStringInfoString(buf, "UNKNOWN");
- break;
}
}
diff --git a/src/backend/access/rmgrdesc/relmapdesc.c b/src/backend/access/rmgrdesc/relmapdesc.c
index 2aebf22..39dcfb5 100644
--- a/src/backend/access/rmgrdesc/relmapdesc.c
+++ b/src/backend/access/rmgrdesc/relmapdesc.c
@@ -26,11 +26,9 @@ relmap_desc(StringInfo buf, XLogRecord *record)
{
xl_relmap_update *xlrec = (xl_relmap_update *) rec;
- appendStringInfo(buf, "update relmap: database %u tablespace %u size %u",
+ appendStringInfo(buf, "database %u tablespace %u size %u",
xlrec->dbid, xlrec->tsid, xlrec->nbytes);
}
- else
- appendStringInfoString(buf, "UNKNOWN");
}
const char *
diff --git a/src/backend/access/rmgrdesc/seqdesc.c b/src/backend/access/rmgrdesc/seqdesc.c
index 157c7c6..d44fe62 100644
--- a/src/backend/access/rmgrdesc/seqdesc.c
+++ b/src/backend/access/rmgrdesc/seqdesc.c
@@ -25,15 +25,9 @@ seq_desc(StringInfo buf, XLogRecord *record)
xl_seq_rec *xlrec = (xl_seq_rec *) rec;
if (info == XLOG_SEQ_LOG)
- appendStringInfoString(buf, "log: ");
- else
- {
- appendStringInfoString(buf, "UNKNOWN");
- return;
- }
-
- appendStringInfo(buf, "rel %u/%u/%u",
- xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
+ appendStringInfo(buf, "rel %u/%u/%u",
+ xlrec->node.spcNode, xlrec->node.dbNode,
+ xlrec->node.relNode);
}
const char *
diff --git a/src/backend/access/rmgrdesc/smgrdesc.c b/src/backend/access/rmgrdesc/smgrdesc.c
index 0a7a6e2..ee711bc 100644
--- a/src/backend/access/rmgrdesc/smgrdesc.c
+++ b/src/backend/access/rmgrdesc/smgrdesc.c
@@ -29,7 +29,7 @@ smgr_desc(StringInfo buf, XLogRecord *record)
xl_smgr_create *xlrec = (xl_smgr_create *) rec;
char *path = relpathperm(xlrec->rnode, xlrec->forkNum);
- appendStringInfo(buf, "file create: %s", path);
+ appendStringInfo(buf, "%s", path);
pfree(path);
}
else if (info == XLOG_SMGR_TRUNCATE)
@@ -37,12 +37,9 @@ smgr_desc(StringInfo buf, XLogRecord *record)
xl_smgr_truncate *xlrec = (xl_smgr_truncate *) rec;
char *path = relpathperm(xlrec->rnode, MAIN_FORKNUM);
- appendStringInfo(buf, "file truncate: %s to %u blocks", path,
- xlrec->blkno);
+ appendStringInfo(buf, "%s to %u blocks", path, xlrec->blkno);
pfree(path);
}
- else
- appendStringInfoString(buf, "UNKNOWN");
}
const char *
diff --git a/src/backend/access/rmgrdesc/spgdesc.c b/src/backend/access/rmgrdesc/spgdesc.c
index 76f43ff..74b2177 100644
--- a/src/backend/access/rmgrdesc/spgdesc.c
+++ b/src/backend/access/rmgrdesc/spgdesc.c
@@ -32,32 +32,32 @@ spg_desc(StringInfo buf, XLogRecord *record)
switch (info)
{
case XLOG_SPGIST_CREATE_INDEX:
- appendStringInfo(buf, "create_index: rel %u/%u/%u",
+ appendStringInfo(buf, "rel %u/%u/%u",
((RelFileNode *) rec)->spcNode,
((RelFileNode *) rec)->dbNode,
((RelFileNode *) rec)->relNode);
break;
case XLOG_SPGIST_ADD_LEAF:
out_target(buf, ((spgxlogAddLeaf *) rec)->node);
- appendStringInfo(buf, "add leaf to page: %u",
+ appendStringInfo(buf, "%u",
((spgxlogAddLeaf *) rec)->blknoLeaf);
break;
case XLOG_SPGIST_MOVE_LEAFS:
out_target(buf, ((spgxlogMoveLeafs *) rec)->node);
- appendStringInfo(buf, "move %u leafs from page %u to page %u",
+ appendStringInfo(buf, "%u leafs from page %u to page %u",
((spgxlogMoveLeafs *) rec)->nMoves,
((spgxlogMoveLeafs *) rec)->blknoSrc,
((spgxlogMoveLeafs *) rec)->blknoDst);
break;
case XLOG_SPGIST_ADD_NODE:
out_target(buf, ((spgxlogAddNode *) rec)->node);
- appendStringInfo(buf, "add node to %u:%u",
+ appendStringInfo(buf, "%u:%u",
((spgxlogAddNode *) rec)->blkno,
((spgxlogAddNode *) rec)->offnum);
break;
case XLOG_SPGIST_SPLIT_TUPLE:
out_target(buf, ((spgxlogSplitTuple *) rec)->node);
- appendStringInfo(buf, "split node %u:%u to %u:%u",
+ appendStringInfo(buf, "%u:%u to %u:%u",
((spgxlogSplitTuple *) rec)->blknoPrefix,
((spgxlogSplitTuple *) rec)->offnumPrefix,
((spgxlogSplitTuple *) rec)->blknoPostfix,
@@ -65,26 +65,22 @@ spg_desc(StringInfo buf, XLogRecord *record)
break;
case XLOG_SPGIST_PICKSPLIT:
out_target(buf, ((spgxlogPickSplit *) rec)->node);
- appendStringInfoString(buf, "split leaf page");
break;
case XLOG_SPGIST_VACUUM_LEAF:
out_target(buf, ((spgxlogVacuumLeaf *) rec)->node);
- appendStringInfo(buf, "vacuum leaf tuples on page %u",
+ appendStringInfo(buf, "page %u",
((spgxlogVacuumLeaf *) rec)->blkno);
break;
case XLOG_SPGIST_VACUUM_ROOT:
out_target(buf, ((spgxlogVacuumRoot *) rec)->node);
- appendStringInfo(buf, "vacuum leaf tuples on root page %u",
+ appendStringInfo(buf, "page %u",
((spgxlogVacuumRoot *) rec)->blkno);
break;
case XLOG_SPGIST_VACUUM_REDIRECT:
out_target(buf, ((spgxlogVacuumRedirect *) rec)->node);
- appendStringInfo(buf, "vacuum redirect tuples on page %u, newest XID %u",
+ appendStringInfo(buf, "page %u, newest XID %u",
((spgxlogVacuumRedirect *) rec)->blkno,
- ((spgxlogVacuumRedirect *) rec)->newestRedirectXid);
- break;
- default:
- appendStringInfo(buf, "unknown spgist op code %u", info);
+ ((spgxlogVacuumRedirect *) rec)->newestRedirectXid);
break;
}
}
diff --git a/src/backend/access/rmgrdesc/standbydesc.c b/src/backend/access/rmgrdesc/standbydesc.c
index 77503d4..436b27c 100644
--- a/src/backend/access/rmgrdesc/standbydesc.c
+++ b/src/backend/access/rmgrdesc/standbydesc.c
@@ -47,10 +47,8 @@ standby_desc(StringInfo buf, XLogRecord *record)
xl_standby_locks *xlrec = (xl_standby_locks *) rec;
int i;
- appendStringInfoString(buf, "AccessExclusive locks:");
-
for (i = 0; i < xlrec->nlocks; i++)
- appendStringInfo(buf, " xid %u db %u rel %u",
+ appendStringInfo(buf, "xid %u db %u rel %u ",
xlrec->locks[i].xid, xlrec->locks[i].dbOid,
xlrec->locks[i].relOid);
}
@@ -58,11 +56,8 @@ standby_desc(StringInfo buf, XLogRecord *record)
{
xl_running_xacts *xlrec = (xl_running_xacts *) rec;
- appendStringInfoString(buf, "running xacts:");
standby_desc_running_xacts(buf, xlrec);
}
- else
- appendStringInfoString(buf, "UNKNOWN");
}
const char *
diff --git a/src/backend/access/rmgrdesc/tblspcdesc.c b/src/backend/access/rmgrdesc/tblspcdesc.c
index c947845..effeaf6 100644
--- a/src/backend/access/rmgrdesc/tblspcdesc.c
+++ b/src/backend/access/rmgrdesc/tblspcdesc.c
@@ -27,17 +27,14 @@ tblspc_desc(StringInfo buf, XLogRecord *record)
{
xl_tblspc_create_rec *xlrec = (xl_tblspc_create_rec *) rec;
- appendStringInfo(buf, "create tablespace: %u \"%s\"",
- xlrec->ts_id, xlrec->ts_path);
+ appendStringInfo(buf, "%u \"%s\"", xlrec->ts_id, xlrec->ts_path);
}
else if (info == XLOG_TBLSPC_DROP)
{
xl_tblspc_drop_rec *xlrec = (xl_tblspc_drop_rec *) rec;
- appendStringInfo(buf, "drop tablespace: %u", xlrec->ts_id);
+ appendStringInfo(buf, "%u", xlrec->ts_id);
}
- else
- appendStringInfoString(buf, "UNKNOWN");
}
const char *
diff --git a/src/backend/access/rmgrdesc/xactdesc.c b/src/backend/access/rmgrdesc/xactdesc.c
index 8ea10c9..11e64af 100644
--- a/src/backend/access/rmgrdesc/xactdesc.c
+++ b/src/backend/access/rmgrdesc/xactdesc.c
@@ -146,39 +146,32 @@ xact_desc(StringInfo buf, XLogRecord *record)
{
xl_xact_commit_compact *xlrec = (xl_xact_commit_compact *) rec;
- appendStringInfoString(buf, "commit: ");
xact_desc_commit_compact(buf, xlrec);
}
else if (info == XLOG_XACT_COMMIT)
{
xl_xact_commit *xlrec = (xl_xact_commit *) rec;
- appendStringInfoString(buf, "commit: ");
xact_desc_commit(buf, xlrec);
}
else if (info == XLOG_XACT_ABORT)
{
xl_xact_abort *xlrec = (xl_xact_abort *) rec;
- appendStringInfoString(buf, "abort: ");
xact_desc_abort(buf, xlrec);
}
- else if (info == XLOG_XACT_PREPARE)
- {
- appendStringInfoString(buf, "prepare");
- }
else if (info == XLOG_XACT_COMMIT_PREPARED)
{
xl_xact_commit_prepared *xlrec = (xl_xact_commit_prepared *) rec;
- appendStringInfo(buf, "commit prepared %u: ", xlrec->xid);
+ appendStringInfo(buf, "%u: ", xlrec->xid);
xact_desc_commit(buf, &xlrec->crec);
}
else if (info == XLOG_XACT_ABORT_PREPARED)
{
xl_xact_abort_prepared *xlrec = (xl_xact_abort_prepared *) rec;
- appendStringInfo(buf, "abort prepared %u: ", xlrec->xid);
+ appendStringInfo(buf, "%u: ", xlrec->xid);
xact_desc_abort(buf, &xlrec->arec);
}
else if (info == XLOG_XACT_ASSIGNMENT)
@@ -190,11 +183,9 @@ xact_desc(StringInfo buf, XLogRecord *record)
* interested in the top-level xid that issued the record and which
* xids are being reported here.
*/
- appendStringInfo(buf, "xid assignment xtop %u: ", xlrec->xtop);
+ appendStringInfo(buf, "xtop %u: ", xlrec->xtop);
xact_desc_assignment(buf, xlrec);
}
- else
- appendStringInfoString(buf, "UNKNOWN");
}
const char *
diff --git a/src/backend/access/rmgrdesc/xlogdesc.c b/src/backend/access/rmgrdesc/xlogdesc.c
index 04a1f24..cdefaf5 100644
--- a/src/backend/access/rmgrdesc/xlogdesc.c
+++ b/src/backend/access/rmgrdesc/xlogdesc.c
@@ -42,7 +42,7 @@ xlog_desc(StringInfo buf, XLogRecord *record)
{
CheckPoint *checkpoint = (CheckPoint *) rec;
- appendStringInfo(buf, "checkpoint: redo %X/%X; "
+ appendStringInfo(buf, "redo %X/%X; "
"tli %u; prev tli %u; fpw %s; xid %u/%u; oid %u; multi %u; offset %u; "
"oldest xid %u in DB %u; oldest multi %u in DB %u; "
"oldest running xid %u; %s",
@@ -61,33 +61,24 @@ xlog_desc(StringInfo buf, XLogRecord *record)
checkpoint->oldestActiveXid,
(info == XLOG_CHECKPOINT_SHUTDOWN) ? "shutdown" : "online");
}
- else if (info == XLOG_NOOP)
- {
- appendStringInfoString(buf, "xlog no-op");
- }
else if (info == XLOG_NEXTOID)
{
Oid nextOid;
memcpy(&nextOid, rec, sizeof(Oid));
- appendStringInfo(buf, "nextOid: %u", nextOid);
- }
- else if (info == XLOG_SWITCH)
- {
- appendStringInfoString(buf, "xlog switch");
+ appendStringInfo(buf, "%u", nextOid);
}
else if (info == XLOG_RESTORE_POINT)
{
xl_restore_point *xlrec = (xl_restore_point *) rec;
- appendStringInfo(buf, "restore point: %s", xlrec->rp_name);
-
+ appendStringInfo(buf, "%s", xlrec->rp_name);
}
else if (info == XLOG_FPI)
{
BkpBlock *bkp = (BkpBlock *) rec;
- appendStringInfo(buf, "full-page image: %s block %u",
+ appendStringInfo(buf, "%s block %u",
relpathperm(bkp->node, bkp->fork),
bkp->block);
}
@@ -96,7 +87,7 @@ xlog_desc(StringInfo buf, XLogRecord *record)
XLogRecPtr startpoint;
memcpy(&startpoint, rec, sizeof(XLogRecPtr));
- appendStringInfo(buf, "backup end: %X/%X",
+ appendStringInfo(buf, "%X/%X",
(uint32) (startpoint >> 32), (uint32) startpoint);
}
else if (info == XLOG_PARAMETER_CHANGE)
@@ -118,7 +109,7 @@ xlog_desc(StringInfo buf, XLogRecord *record)
}
}
- appendStringInfo(buf, "parameter change: max_connections=%d max_worker_processes=%d max_prepared_xacts=%d max_locks_per_xact=%d wal_level=%s",
+ appendStringInfo(buf, "max_connections=%d max_worker_processes=%d max_prepared_xacts=%d max_locks_per_xact=%d wal_level=%s",
xlrec.MaxConnections,
xlrec.max_worker_processes,
xlrec.max_prepared_xacts,
@@ -130,19 +121,17 @@ xlog_desc(StringInfo buf, XLogRecord *record)
bool fpw;
memcpy(&fpw, rec, sizeof(bool));
- appendStringInfo(buf, "full_page_writes: %s", fpw ? "true" : "false");
+ appendStringInfo(buf, "%s", fpw ? "true" : "false");
}
else if (info == XLOG_END_OF_RECOVERY)
{
xl_end_of_recovery xlrec;
memcpy(&xlrec, rec, sizeof(xl_end_of_recovery));
- appendStringInfo(buf, "end_of_recovery: tli %u; prev tli %u; time %s",
+ appendStringInfo(buf, "tli %u; prev tli %u; time %s",
xlrec.ThisTimeLineID, xlrec.PrevTimeLineID,
timestamptz_to_str(xlrec.end_time));
}
- else
- appendStringInfoString(buf, "UNKNOWN");
}
const char *
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 34f2fc0..1265eca 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -799,6 +799,7 @@ static bool CheckForStandbyTrigger(void);
#ifdef WAL_DEBUG
static void xlog_outrec(StringInfo buf, XLogRecord *record);
#endif
+static void xlog_outdesc(StringInfo buf, RmgrId rmid, XLogRecord *record);
static void pg_start_backup_callback(int code, Datum arg);
static bool read_backup_label(XLogRecPtr *checkPointLoc,
bool *backupEndRequired, bool *backupFromStandby);
@@ -1287,7 +1288,7 @@ begin:;
appendBinaryStringInfo(&recordbuf, rdata->data, rdata->len);
appendStringInfoString(&buf, " - ");
- RmgrTable[rechdr->xl_rmid].rm_desc(&buf, (XLogRecord *) recordbuf.data);
+ xlog_outdesc(&buf, rechdr->xl_rmid, (XLogRecord *) recordbuf.data);
}
elog(LOG, "%s", buf.data);
@@ -6710,7 +6711,7 @@ StartupXLOG(void)
(uint32) (EndRecPtr >> 32), (uint32) EndRecPtr);
xlog_outrec(&buf, record);
appendStringInfoString(&buf, " - ");
- RmgrTable[record->xl_rmid].rm_desc(&buf, record);
+ xlog_outdesc(&buf, record->xl_rmid, record);
elog(LOG, "%s", buf.data);
pfree(buf.data);
}
@@ -9629,6 +9630,35 @@ xlog_outrec(StringInfo buf, XLogRecord *record)
}
#endif /* WAL_DEBUG */
+/*
+ * Returns a string describing an XLogRecord, consisting of its identity
+ * optionally followed by a colon, a space, and a further description.
+ */
+static void
+xlog_outdesc(StringInfo buf, RmgrId rmid, XLogRecord *record)
+{
+ const char *id;
+
+ id = RmgrTable[rmid].rm_identify(record->xl_info);
+ if (id == NULL)
+ appendStringInfo(buf, "%X", record->xl_info);
+ else
+ {
+ StringInfoData desc;
+
+ initStringInfo(&desc);
+ RmgrTable[rmid].rm_desc(&desc, record);
+
+ appendStringInfoString(buf, id);
+ if (desc.len > 0)
+ {
+ appendStringInfoString(buf, ": ");
+ appendStringInfoString(buf, desc.data);
+ pfree(desc.data);
+ }
+ }
+}
+
/*
* Return the (possible) sync flag used for opening a file, depending on the
@@ -10664,7 +10694,7 @@ rm_redo_error_callback(void *arg)
StringInfoData buf;
initStringInfo(&buf);
- RmgrTable[record->xl_rmid].rm_desc(&buf, record);
+ xlog_outdesc(&buf, record->xl_rmid, record);
/* don't bother emitting empty description */
if (buf.len > 0)
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index d53520a..fd0553a 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -239,6 +239,12 @@ struct XLogRecord;
* This struct must be kept in sync with the PG_RMGR definition in
* rmgr.c.
*
+ * rm_identify must return a name for the record based on xl_info
+ * (without reference to the rmid). For example, XLOG_BTREE_VACUUM
+ * would be named "VACUUM". rm_desc can then be called to obtain
+ * additional detail for the record, if available (e.g. the last
+ * block).
+ *
* RmgrTable[] is indexed by RmgrId values (see rmgrlist.h).
*/
typedef struct RmgrData
--
1.9.1
On 2014-09-19 13:24:11 +0530, Abhijit Menon-Sen wrote:
diff --git a/configure.in b/configure.in index 1392277..c3c458c 100644 --- a/configure.in +++ b/configure.in @@ -1637,7 +1637,7 @@ fi # If we found "long int" is 64 bits, assume snprintf handles it. If # we found we need to use "long long int", better check. We cope with # snprintfs that use %lld, %qd, or %I64d as the format. If none of these -# work, fall back to our own snprintf emulation (which we know uses %lld). +# works, fall back to our own snprintf emulation (which we know uses %lld).
spurious independent change? Also I actually think the original version
is correct?
+typedef struct XLogDumpStats +{ + uint64 count; + Stats rmgr_stats[RM_NEXT_ID]; + Stats record_stats[RM_NEXT_ID][16]; +} XLogDumpStats;
I dislike the literal 16 here and someplace later. A define for the max
number of records would make it clearer.
/* + * Store per-rmgr and per-record statistics for a given record. + */ +static void +XLogDumpCountRecord(XLogDumpConfig *config, XLogDumpStats *stats, XLogRecPtr ReadRecPtr, XLogRecord *record) +{ + RmgrId rmid; + uint8 recid; + + if (config->filter_by_rmgr != -1 && + config->filter_by_rmgr != record->xl_rmid) + return; + + if (config->filter_by_xid_enabled && + config->filter_by_xid != record->xl_xid) + return;
Perhaps we should move these kind of checks outside? So
XLogDumpDisplayRecord and this don't have to repeat them. I sure hope
we'll get some more. I e.g. really, really would like to have a
relfilenode check once Heikki's changes to make that possible are in.
+ stats->count++; + + /* Update per-rmgr statistics */ + + rmid = record->xl_rmid; + + stats->rmgr_stats[rmid].count++; + stats->rmgr_stats[rmid].rec_len += + record->xl_len + SizeOfXLogRecord; + stats->rmgr_stats[rmid].fpi_len += + record->xl_tot_len - (record->xl_len + SizeOfXLogRecord);
a) Whoever introduced the notion of rec_len vs tot_len in regards to
including/excluding SizeOfXLogRecord ...
b) I'm not against it, but I wonder if the best way to add the
SizeOfXLogRecord to the record size. It's just as much part of the
FPI. And this means that the record length will be > 0 even if all
the record data has been removed due to the FPI.
static void usage(void) { @@ -401,6 +581,8 @@ usage(void) printf(" (default: 1 or the value used in STARTSEG)\n"); printf(" -V, --version output version information, then exit\n"); printf(" -x, --xid=XID only show records with TransactionId XID\n"); + printf(" -z, --stats show per-rmgr statistics\n"); + printf(" -Z, --record-stats show per-record statistics\n"); printf(" -?, --help show this help, then exit\n"); }
What was the reason you moved away from --stats=record/rmgr? I think we
possibly will add further ones, so that seems more
extensible?
diff --git a/contrib/pg_xlogdump/rmgrdesc.c b/contrib/pg_xlogdump/rmgrdesc.c index cbcaaa6..dc27fd1 100644 --- a/contrib/pg_xlogdump/rmgrdesc.c +++ b/contrib/pg_xlogdump/rmgrdesc.c
It's trivial to separate in this case, but I'd much rather have patches
like this rm_identity stuff split up in the future.
diff --git a/src/backend/access/rmgrdesc/heapdesc.c b/src/backend/access/rmgrdesc/heapdesc.c index 24b6f92..91a8e72 100644 --- a/src/backend/access/rmgrdesc/heapdesc.c +++ b/src/backend/access/rmgrdesc/heapdesc.c @@ -193,3 +193,86 @@ heap2_desc(StringInfo buf, XLogRecord *record) else appendStringInfoString(buf, "UNKNOWN"); } + +static const char * +append_init(const char *str) +{ + static char x[32]; + + strcpy(x, str); + strcat(x, "+INIT"); + + return x; +} + +const char * +heap_identify(uint8 info) +{ + const char *id = NULL; + + switch (info & XLOG_HEAP_OPMASK) + { + case XLOG_HEAP_INSERT: + id = "INSERT"; + break; + case XLOG_HEAP_DELETE: + id = "DELETE"; + break; + case XLOG_HEAP_UPDATE: + id = "UPDATE"; + break; + case XLOG_HEAP_HOT_UPDATE: + id = "HOT_UPDATE"; + break; + case XLOG_HEAP_LOCK: + id = "LOCK"; + break; + case XLOG_HEAP_INPLACE: + id = "INPLACE"; + break; + } + + if (info & XLOG_HEAP_INIT_PAGE) + id = append_init(id); + + return id; +}
Hm. I'm a bit doubtful about the static buffer used in
append_init(). That means the returned value from heap_identity() is
only valid until the next call. That at the very least needs to be
written down explicitly somewhere.
diff --git a/src/include/c.h b/src/include/c.h index 2ceaaf6..cf3cbd1 100644 --- a/src/include/c.h +++ b/src/include/c.h @@ -867,6 +867,9 @@ typedef NameData *Name; * ---------------------------------------------------------------- */+#define INT64_FORMAT "%" INT64_MODIFIER "d" +#define UINT64_FORMAT "%" INT64_MODIFIER "u" +
That's already in there afaics:
/* snprintf format strings to use for 64-bit integers */
#define INT64_FORMAT "%" INT64_MODIFIER "d"
#define UINT64_FORMAT "%" INT64_MODIFIER "u"
+/* + * Returns a string describing an XLogRecord, consisting of its identity + * optionally followed by a colon, a space, and a further description. + */ +static void +xlog_outdesc(StringInfo buf, RmgrId rmid, XLogRecord *record) +{ + const char *id; + + id = RmgrTable[rmid].rm_identify(record->xl_info); + if (id == NULL) + appendStringInfo(buf, "%X", record->xl_info);
Given that you've removed the UNKNOWNs from the rm_descs, this really
should add it here.
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
At 2014-09-19 13:24:11 +0530, ams@2ndQuadrant.com wrote:
Good enough?
Not quite. I've attached a small additional patch that shifts the
responsibility of adding rm_name to the output from xlog_outrec to
xlog_outdesc. Now we get WAL_DEBUG output like this:
LOG: INSERT @ 0/16C51D0: prev 0/16C5160; xid 692; len 31: Heap/INSERT: rel 1663/16384/16385; tid 0/5
…which is consistent with pg_xlogdump --stats output too.
-- Abhijit
Attachments:
move-rm-name.difftext/x-diff; charset=us-asciiDownload
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 1265eca..b9bf206 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -1287,7 +1287,7 @@ begin:;
for (; rdata != NULL; rdata = rdata->next)
appendBinaryStringInfo(&recordbuf, rdata->data, rdata->len);
- appendStringInfoString(&buf, " - ");
+ appendStringInfoString(&buf, ": ");
xlog_outdesc(&buf, rechdr->xl_rmid, (XLogRecord *) recordbuf.data);
}
elog(LOG, "%s", buf.data);
@@ -6710,7 +6710,7 @@ StartupXLOG(void)
(uint32) (ReadRecPtr >> 32), (uint32) ReadRecPtr,
(uint32) (EndRecPtr >> 32), (uint32) EndRecPtr);
xlog_outrec(&buf, record);
- appendStringInfoString(&buf, " - ");
+ appendStringInfoString(&buf, ": ");
xlog_outdesc(&buf, record->xl_rmid, record);
elog(LOG, "%s", buf.data);
pfree(buf.data);
@@ -9625,8 +9625,6 @@ xlog_outrec(StringInfo buf, XLogRecord *record)
if (record->xl_info & XLR_BKP_BLOCK(i))
appendStringInfo(buf, "; bkpb%d", i);
}
-
- appendStringInfo(buf, ": %s", RmgrTable[record->xl_rmid].rm_name);
}
#endif /* WAL_DEBUG */
@@ -9639,6 +9637,9 @@ xlog_outdesc(StringInfo buf, RmgrId rmid, XLogRecord *record)
{
const char *id;
+ appendStringInfoString(buf, RmgrTable[rmid].rm_name);
+ appendStringInfoChar(buf, '/');
+
id = RmgrTable[rmid].rm_identify(record->xl_info);
if (id == NULL)
appendStringInfo(buf, "%X", record->xl_info);
At 2014-09-19 10:44:48 +0200, andres@2ndquadrant.com wrote:
# snprintfs that use %lld, %qd, or %I64d as the format. If none of these -# work, fall back to our own snprintf emulation (which we know uses %lld). +# works, fall back to our own snprintf emulation (which we know uses %lld).spurious independent change?
It was part of the original patch, but I guess Heikki didn't commit it,
so it was left over in the rebase.
Also I actually think the original version is correct?
It is not. I suspect it will begin to sound wrong to you if you replace
"none" with "not one" in the sentence. But I don't care enough to argue
about it. It's a very common error.
+ Stats record_stats[RM_NEXT_ID][16];
+} XLogDumpStats;I dislike the literal 16 here and someplace later. A define for the max
number of records would make it clearer.
OK, will change.
Perhaps we should move these kind of checks outside?
OK, will change.
a) Whoever introduced the notion of rec_len vs tot_len in regards to
including/excluding SizeOfXLogRecord ...
(It wasn't me, honest!)
b) I'm not against it, but I wonder if the best way to add the
SizeOfXLogRecord to the record size. It's just as much part of the
FPI. And this means that the record length will be > 0 even if all
the record data has been removed due to the FPI.
I'm not sure I understand what you are proposing here.
What was the reason you moved away from --stats=record/rmgr? I think
we possibly will add further ones, so that seems more extensible?
It was because I wanted --stats to default to "=rmgr", so I tried to
make the argument optional, but getopt in Windows didn't like that.
Here's an excerpt from the earlier discussion:
3. Some compilation error in windows
.\contrib\pg_xlogdump\pg_xlogdump.c(1002) : error C2065: 'optional_argument' : undeclared identifier
.\contrib\pg_xlogdump\pg_xlogdump.c(1002) : error C2099: initializer is not a constantoptional_argument should be added to getopt_long.h file for windows.
Hmm. I have no idea what to do about this. I did notice when I wrote the
code that nothing else used optional_argument, but I didn't realise that
it wouldn't work on Windows.
It may be that the best thing to do would be to avoid using
optional_argument altogether, and have separate --stats and
--stats-per-record options. Thoughts?
I have no objection to doing it differently if someone tells me how to
make Windows happy (preferably without making me unhappy).
It's trivial to separate in this case, but I'd much rather have
patches like this rm_identity stuff split up in the future.
Sorry. I'd split it up that way in the past, but forgot to do it again
in this round. Will do when I resend with the changes above.
That means the returned value from heap_identity() is only valid until
the next call. That at the very least needs to be written down
explicitly somewhere.
Where? In the comment in xlog_internal.h, perhaps?
That's already in there afaics:
Will fix (rebase cruft).
Given that you've removed the UNKNOWNs from the rm_descs, this really
should add it here.
You would prefer to see HEAP/UNKNOWN rather than HEAP/32 for an
unidentifiable xl_info?
-- Abhijit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hi,
On 2014-09-19 14:38:29 +0530, Abhijit Menon-Sen wrote:
b) I'm not against it, but I wonder if the best way to add the
SizeOfXLogRecord to the record size. It's just as much part of the
FPI. And this means that the record length will be > 0 even if all
the record data has been removed due to the FPI.I'm not sure I understand what you are proposing here.
I'm not really proposing anything. I'm just stating that it's
notationally not clear and might be improved. Doesn't need to be now.
What was the reason you moved away from --stats=record/rmgr? I think
we possibly will add further ones, so that seems more extensible?It was because I wanted --stats to default to "=rmgr", so I tried to
make the argument optional, but getopt in Windows didn't like that.
Here's an excerpt from the earlier discussion:3. Some compilation error in windows
.\contrib\pg_xlogdump\pg_xlogdump.c(1002) : error C2065: 'optional_argument' : undeclared identifier
.\contrib\pg_xlogdump\pg_xlogdump.c(1002) : error C2099: initializer is not a constantoptional_argument should be added to getopt_long.h file for windows.
Hmm. I have no idea what to do about this. I did notice when I wrote the
code that nothing else used optional_argument, but I didn't realise that
it wouldn't work on Windows.It may be that the best thing to do would be to avoid using
optional_argument altogether, and have separate --stats and
--stats-per-record options. Thoughts?
Oh, I've since implemented optional arguments for windows/replacement
getopt_long. It's used by psql since a week or so ago.
I have no objection to doing it differently if someone tells me how to
make Windows happy (preferably without making me unhappy).
[x] Done
Given that you've removed the UNKNOWNs from the rm_descs, this really
should add it here.You would prefer to see HEAP/UNKNOWN rather than HEAP/32 for an
unidentifiable xl_info?
UNKNOWN (32)? It should visually stand out more than just the
number. Somebody borked something if that happens.
Greetings,
Andres Freund
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
I've attached the revised patch, split up differently:
1. Introduce rm_identify, change rm_desc, glue the two together in
xlog.c
2. Introduce pg_xlogdump --stats[=record].
The requested changes (16, filter, z:, UNKNOWN) are included. The
grammar nitpicking and rebase cruft is^Ware^Wain't included.
I ran Postgres with WAL_DEBUG for a while, and I ran pg_xlogdump with
--stats (and --stats=rmgr) and --stats=record with and without a few
different variants of "-r heap". Everything looked OK to me.
I hope I didn't miss anything this time.
-- Abhijit
Attachments:
0001-Introduce-an-RmgrDescData.rm_identify-callback-to-na.patchtext/x-diff; charset=utf-8Download
>From da6df2f24bb8ea768d6e7671474b0ad7d0b798d1 Mon Sep 17 00:00:00 2001
From: Abhijit Menon-Sen <ams@2ndQuadrant.com>
Date: Fri, 19 Sep 2014 15:08:45 +0530
Subject: Introduce an RmgrDescData.rm_identify callback to name records
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
For example, rm_identify turns XLOG_BTREE_VACUUM into "VACUUM" based on
xl_info. rm_desc now omits the prefix that (unsystematically) duplicated
the rm_identity output, and only provides extra detail if available:
LOG: INSERT @ 0/16C50F0: prev 0/16C5080; xid 690; len 31: Heap/INSERT: rel 1663/16384/16385; tid 0/3
In the above, "Heap" comes from rm_name, "INSERT" comes from
rm_identify, and "rel 1663/â¦" comes from rm_desc.
The three are glued together by a new xlog_outdesc function in xlog.c.
---
contrib/pg_xlogdump/rmgrdesc.c | 2 +-
src/backend/access/rmgrdesc/clogdesc.c | 27 ++++---
src/backend/access/rmgrdesc/dbasedesc.c | 24 +++++-
src/backend/access/rmgrdesc/gindesc.c | 54 ++++++++++---
src/backend/access/rmgrdesc/gistdesc.c | 25 +++++-
src/backend/access/rmgrdesc/hashdesc.c | 6 ++
src/backend/access/rmgrdesc/heapdesc.c | 123 +++++++++++++++++++++--------
src/backend/access/rmgrdesc/mxactdesc.c | 37 ++++++---
src/backend/access/rmgrdesc/nbtdesc.c | 124 +++++++++++++++---------------
src/backend/access/rmgrdesc/relmapdesc.c | 19 ++++-
src/backend/access/rmgrdesc/seqdesc.c | 21 +++--
src/backend/access/rmgrdesc/smgrdesc.c | 25 ++++--
src/backend/access/rmgrdesc/spgdesc.c | 59 +++++++++++---
src/backend/access/rmgrdesc/standbydesc.c | 25 ++++--
src/backend/access/rmgrdesc/tblspcdesc.c | 25 ++++--
src/backend/access/rmgrdesc/xactdesc.c | 48 +++++++++---
src/backend/access/rmgrdesc/xlogdesc.c | 72 ++++++++++++-----
src/backend/access/transam/rmgr.c | 4 +-
src/backend/access/transam/xlog.c | 45 +++++++++--
src/include/access/clog.h | 1 +
src/include/access/gin.h | 1 +
src/include/access/gist_private.h | 1 +
src/include/access/hash.h | 1 +
src/include/access/heapam_xlog.h | 2 +
src/include/access/multixact.h | 1 +
src/include/access/nbtree.h | 1 +
src/include/access/rmgr.h | 2 +-
src/include/access/rmgrlist.h | 34 ++++----
src/include/access/spgist.h | 1 +
src/include/access/xact.h | 1 +
src/include/access/xlog.h | 1 +
src/include/access/xlog_internal.h | 11 +++
src/include/catalog/storage_xlog.h | 1 +
src/include/commands/dbcommands.h | 1 +
src/include/commands/sequence.h | 1 +
src/include/commands/tablespace.h | 1 +
src/include/storage/standby.h | 1 +
src/include/utils/relmapper.h | 1 +
38 files changed, 597 insertions(+), 232 deletions(-)
diff --git a/contrib/pg_xlogdump/rmgrdesc.c b/contrib/pg_xlogdump/rmgrdesc.c
index cbcaaa6..1064d34 100644
--- a/contrib/pg_xlogdump/rmgrdesc.c
+++ b/contrib/pg_xlogdump/rmgrdesc.c
@@ -27,7 +27,7 @@
#include "storage/standby.h"
#include "utils/relmapper.h"
-#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \
+#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \
{ name, desc, },
const RmgrDescData RmgrDescTable[RM_MAX_ID + 1] = {
diff --git a/src/backend/access/rmgrdesc/clogdesc.c b/src/backend/access/rmgrdesc/clogdesc.c
index e82baa8..8beb6d0 100644
--- a/src/backend/access/rmgrdesc/clogdesc.c
+++ b/src/backend/access/rmgrdesc/clogdesc.c
@@ -23,20 +23,29 @@ clog_desc(StringInfo buf, XLogRecord *record)
char *rec = XLogRecGetData(record);
uint8 info = record->xl_info & ~XLR_INFO_MASK;
- if (info == CLOG_ZEROPAGE)
+ if (info == CLOG_ZEROPAGE || info == CLOG_TRUNCATE)
{
int pageno;
memcpy(&pageno, rec, sizeof(int));
- appendStringInfo(buf, "zeropage: %d", pageno);
+ appendStringInfo(buf, "%d", pageno);
}
- else if (info == CLOG_TRUNCATE)
- {
- int pageno;
+}
- memcpy(&pageno, rec, sizeof(int));
- appendStringInfo(buf, "truncate before: %d", pageno);
+const char *
+clog_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case CLOG_ZEROPAGE:
+ id = "ZEROPAGE";
+ break;
+ case CLOG_TRUNCATE:
+ id = "TRUNCATE";
+ break;
}
- else
- appendStringInfoString(buf, "UNKNOWN");
+
+ return id;
}
diff --git a/src/backend/access/rmgrdesc/dbasedesc.c b/src/backend/access/rmgrdesc/dbasedesc.c
index 0230716..e36988a 100644
--- a/src/backend/access/rmgrdesc/dbasedesc.c
+++ b/src/backend/access/rmgrdesc/dbasedesc.c
@@ -28,7 +28,7 @@ dbase_desc(StringInfo buf, XLogRecord *record)
{
xl_dbase_create_rec *xlrec = (xl_dbase_create_rec *) rec;
- appendStringInfo(buf, "create db: copy dir %u/%u to %u/%u",
+ appendStringInfo(buf, "copy dir %u/%u to %u/%u",
xlrec->src_db_id, xlrec->src_tablespace_id,
xlrec->db_id, xlrec->tablespace_id);
}
@@ -36,9 +36,25 @@ dbase_desc(StringInfo buf, XLogRecord *record)
{
xl_dbase_drop_rec *xlrec = (xl_dbase_drop_rec *) rec;
- appendStringInfo(buf, "drop db: dir %u/%u",
+ appendStringInfo(buf, "dir %u/%u",
xlrec->db_id, xlrec->tablespace_id);
}
- else
- appendStringInfoString(buf, "UNKNOWN");
+}
+
+const char *
+dbase_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_DBASE_CREATE:
+ id = "CREATE";
+ break;
+ case XLOG_DBASE_DROP:
+ id = "DROP";
+ break;
+ }
+
+ return id;
}
diff --git a/src/backend/access/rmgrdesc/gindesc.c b/src/backend/access/rmgrdesc/gindesc.c
index 12d68d7..dd4c791 100644
--- a/src/backend/access/rmgrdesc/gindesc.c
+++ b/src/backend/access/rmgrdesc/gindesc.c
@@ -85,11 +85,9 @@ gin_desc(StringInfo buf, XLogRecord *record)
switch (info)
{
case XLOG_GIN_CREATE_INDEX:
- appendStringInfoString(buf, "Create index, ");
desc_node(buf, *(RelFileNode *) rec, GIN_ROOT_BLKNO);
break;
case XLOG_GIN_CREATE_PTREE:
- appendStringInfoString(buf, "Create posting tree, ");
desc_node(buf, ((ginxlogCreatePostingTree *) rec)->node, ((ginxlogCreatePostingTree *) rec)->blkno);
break;
case XLOG_GIN_INSERT:
@@ -97,7 +95,6 @@ gin_desc(StringInfo buf, XLogRecord *record)
ginxlogInsert *xlrec = (ginxlogInsert *) rec;
char *payload = rec + sizeof(ginxlogInsert);
- appendStringInfoString(buf, "Insert item, ");
desc_node(buf, xlrec->node, xlrec->blkno);
appendStringInfo(buf, " isdata: %c isleaf: %c",
(xlrec->flags & GIN_INSERT_ISDATA) ? 'T' : 'F',
@@ -142,7 +139,6 @@ gin_desc(StringInfo buf, XLogRecord *record)
{
ginxlogSplit *xlrec = (ginxlogSplit *) rec;
- appendStringInfoString(buf, "Page split, ");
desc_node(buf, ((ginxlogSplit *) rec)->node, ((ginxlogSplit *) rec)->lblkno);
appendStringInfo(buf, " isrootsplit: %c", (((ginxlogSplit *) rec)->flags & GIN_SPLIT_ROOT) ? 'T' : 'F');
appendStringInfo(buf, " isdata: %c isleaf: %c",
@@ -151,14 +147,12 @@ gin_desc(StringInfo buf, XLogRecord *record)
}
break;
case XLOG_GIN_VACUUM_PAGE:
- appendStringInfoString(buf, "Vacuum page, ");
desc_node(buf, ((ginxlogVacuumPage *) rec)->node, ((ginxlogVacuumPage *) rec)->blkno);
break;
case XLOG_GIN_VACUUM_DATA_LEAF_PAGE:
{
ginxlogVacuumDataLeafPage *xlrec = (ginxlogVacuumDataLeafPage *) rec;
- appendStringInfoString(buf, "Vacuum data leaf page, ");
desc_node(buf, xlrec->node, xlrec->blkno);
if (record->xl_info & XLR_BKP_BLOCK(0))
appendStringInfo(buf, " (full page image)");
@@ -167,23 +161,59 @@ gin_desc(StringInfo buf, XLogRecord *record)
}
break;
case XLOG_GIN_DELETE_PAGE:
- appendStringInfoString(buf, "Delete page, ");
desc_node(buf, ((ginxlogDeletePage *) rec)->node, ((ginxlogDeletePage *) rec)->blkno);
break;
case XLOG_GIN_UPDATE_META_PAGE:
- appendStringInfoString(buf, "Update metapage, ");
desc_node(buf, ((ginxlogUpdateMeta *) rec)->node, GIN_METAPAGE_BLKNO);
break;
case XLOG_GIN_INSERT_LISTPAGE:
- appendStringInfoString(buf, "Insert new list page, ");
desc_node(buf, ((ginxlogInsertListPage *) rec)->node, ((ginxlogInsertListPage *) rec)->blkno);
break;
case XLOG_GIN_DELETE_LISTPAGE:
- appendStringInfo(buf, "Delete list pages (%d), ", ((ginxlogDeleteListPages *) rec)->ndeleted);
+ appendStringInfo(buf, "%d pages, ", ((ginxlogDeleteListPages *) rec)->ndeleted);
desc_node(buf, ((ginxlogDeleteListPages *) rec)->node, GIN_METAPAGE_BLKNO);
break;
- default:
- appendStringInfo(buf, "unknown gin op code %u", info);
+ }
+}
+
+const char *
+gin_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_GIN_CREATE_INDEX:
+ id = "CREATE_INDEX";
+ break;
+ case XLOG_GIN_CREATE_PTREE:
+ id = "CREATE_PTREE";
+ break;
+ case XLOG_GIN_INSERT:
+ id = "INSERT";
+ break;
+ case XLOG_GIN_SPLIT:
+ id = "SPLIT";
+ break;
+ case XLOG_GIN_VACUUM_PAGE:
+ id = "VACUUM_PAGE";
+ break;
+ case XLOG_GIN_VACUUM_DATA_LEAF_PAGE:
+ id = "VACUUM_DATA_LEAF_PAGE";
+ break;
+ case XLOG_GIN_DELETE_PAGE:
+ id = "DELETE_PAGE";
+ break;
+ case XLOG_GIN_UPDATE_META_PAGE:
+ id = "UPDATE_META_PAGE";
+ break;
+ case XLOG_GIN_INSERT_LISTPAGE:
+ id = "INSERT_LISTPAGE";
+ break;
+ case XLOG_GIN_DELETE_LISTPAGE:
+ id = "DELETE_LISTPAGE";
break;
}
+
+ return id;
}
diff --git a/src/backend/access/rmgrdesc/gistdesc.c b/src/backend/access/rmgrdesc/gistdesc.c
index cdac496..f2ed1f6 100644
--- a/src/backend/access/rmgrdesc/gistdesc.c
+++ b/src/backend/access/rmgrdesc/gistdesc.c
@@ -50,20 +50,37 @@ gist_desc(StringInfo buf, XLogRecord *record)
switch (info)
{
case XLOG_GIST_PAGE_UPDATE:
- appendStringInfoString(buf, "page_update: ");
out_gistxlogPageUpdate(buf, (gistxlogPageUpdate *) rec);
break;
case XLOG_GIST_PAGE_SPLIT:
out_gistxlogPageSplit(buf, (gistxlogPageSplit *) rec);
break;
case XLOG_GIST_CREATE_INDEX:
- appendStringInfo(buf, "create_index: rel %u/%u/%u",
+ appendStringInfo(buf, "rel %u/%u/%u",
((RelFileNode *) rec)->spcNode,
((RelFileNode *) rec)->dbNode,
((RelFileNode *) rec)->relNode);
break;
- default:
- appendStringInfo(buf, "unknown gist op code %u", info);
+ }
+}
+
+const char *
+gist_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_GIST_PAGE_UPDATE:
+ id = "PAGE_UPDATE";
+ break;
+ case XLOG_GIST_PAGE_SPLIT:
+ id = "PAGE_SPLIT";
+ break;
+ case XLOG_GIST_CREATE_INDEX:
+ id = "CREATE_INDEX";
break;
}
+
+ return id;
}
diff --git a/src/backend/access/rmgrdesc/hashdesc.c b/src/backend/access/rmgrdesc/hashdesc.c
index 86a0376..c58461c 100644
--- a/src/backend/access/rmgrdesc/hashdesc.c
+++ b/src/backend/access/rmgrdesc/hashdesc.c
@@ -20,3 +20,9 @@ void
hash_desc(StringInfo buf, XLogRecord *record)
{
}
+
+const char *
+hash_identify(uint8 info)
+{
+ return NULL;
+}
diff --git a/src/backend/access/rmgrdesc/heapdesc.c b/src/backend/access/rmgrdesc/heapdesc.c
index 24b6f92..cd9d59d 100644
--- a/src/backend/access/rmgrdesc/heapdesc.c
+++ b/src/backend/access/rmgrdesc/heapdesc.c
@@ -51,17 +51,12 @@ heap_desc(StringInfo buf, XLogRecord *record)
{
xl_heap_insert *xlrec = (xl_heap_insert *) rec;
- if (record->xl_info & XLOG_HEAP_INIT_PAGE)
- appendStringInfoString(buf, "insert(init): ");
- else
- appendStringInfoString(buf, "insert: ");
out_target(buf, &(xlrec->target));
}
else if (info == XLOG_HEAP_DELETE)
{
xl_heap_delete *xlrec = (xl_heap_delete *) rec;
- appendStringInfoString(buf, "delete: ");
out_target(buf, &(xlrec->target));
appendStringInfoChar(buf, ' ');
out_infobits(buf, xlrec->infobits_set);
@@ -70,10 +65,6 @@ heap_desc(StringInfo buf, XLogRecord *record)
{
xl_heap_update *xlrec = (xl_heap_update *) rec;
- if (record->xl_info & XLOG_HEAP_INIT_PAGE)
- appendStringInfoString(buf, "update(init): ");
- else
- appendStringInfoString(buf, "update: ");
out_target(buf, &(xlrec->target));
appendStringInfo(buf, " xmax %u ", xlrec->old_xmax);
out_infobits(buf, xlrec->old_infobits_set);
@@ -86,10 +77,6 @@ heap_desc(StringInfo buf, XLogRecord *record)
{
xl_heap_update *xlrec = (xl_heap_update *) rec;
- if (record->xl_info & XLOG_HEAP_INIT_PAGE) /* can this case happen? */
- appendStringInfoString(buf, "hot_update(init): ");
- else
- appendStringInfoString(buf, "hot_update: ");
out_target(buf, &(xlrec->target));
appendStringInfo(buf, " xmax %u ", xlrec->old_xmax);
out_infobits(buf, xlrec->old_infobits_set);
@@ -102,7 +89,7 @@ heap_desc(StringInfo buf, XLogRecord *record)
{
xl_heap_lock *xlrec = (xl_heap_lock *) rec;
- appendStringInfo(buf, "lock %u: ", xlrec->locking_xid);
+ appendStringInfo(buf, "xid %u: ", xlrec->locking_xid);
out_target(buf, &(xlrec->target));
appendStringInfoChar(buf, ' ');
out_infobits(buf, xlrec->infobits_set);
@@ -111,11 +98,8 @@ heap_desc(StringInfo buf, XLogRecord *record)
{
xl_heap_inplace *xlrec = (xl_heap_inplace *) rec;
- appendStringInfoString(buf, "inplace: ");
out_target(buf, &(xlrec->target));
}
- else
- appendStringInfoString(buf, "UNKNOWN");
}
void
heap2_desc(StringInfo buf, XLogRecord *record)
@@ -128,7 +112,7 @@ heap2_desc(StringInfo buf, XLogRecord *record)
{
xl_heap_clean *xlrec = (xl_heap_clean *) rec;
- appendStringInfo(buf, "clean: rel %u/%u/%u; blk %u remxid %u",
+ appendStringInfo(buf, "rel %u/%u/%u; blk %u remxid %u",
xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->node.relNode, xlrec->block,
xlrec->latestRemovedXid);
@@ -137,27 +121,22 @@ heap2_desc(StringInfo buf, XLogRecord *record)
{
xl_heap_freeze_page *xlrec = (xl_heap_freeze_page *) rec;
- appendStringInfo(buf, "freeze_page: rel %u/%u/%u; blk %u; cutoff xid %u ntuples %u",
+ appendStringInfo(buf, "rel %u/%u/%u; blk %u; cutoff xid %u ntuples %u",
xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->node.relNode, xlrec->block,
xlrec->cutoff_xid, xlrec->ntuples);
}
- else if (info == XLOG_HEAP2_REWRITE)
- {
- appendStringInfoString(buf, "heap rewrite:");
- }
else if (info == XLOG_HEAP2_CLEANUP_INFO)
{
xl_heap_cleanup_info *xlrec = (xl_heap_cleanup_info *) rec;
- appendStringInfo(buf, "cleanup info: remxid %u",
- xlrec->latestRemovedXid);
+ appendStringInfo(buf, "remxid %u", xlrec->latestRemovedXid);
}
else if (info == XLOG_HEAP2_VISIBLE)
{
xl_heap_visible *xlrec = (xl_heap_visible *) rec;
- appendStringInfo(buf, "visible: rel %u/%u/%u; blk %u",
+ appendStringInfo(buf, "rel %u/%u/%u; blk %u",
xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->node.relNode, xlrec->block);
}
@@ -165,10 +144,6 @@ heap2_desc(StringInfo buf, XLogRecord *record)
{
xl_heap_multi_insert *xlrec = (xl_heap_multi_insert *) rec;
- if (record->xl_info & XLOG_HEAP_INIT_PAGE)
- appendStringInfoString(buf, "multi-insert (init): ");
- else
- appendStringInfoString(buf, "multi-insert: ");
appendStringInfo(buf, "rel %u/%u/%u; blk %u; %d tuples",
xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
xlrec->blkno, xlrec->ntuples);
@@ -177,7 +152,7 @@ heap2_desc(StringInfo buf, XLogRecord *record)
{
xl_heap_lock_updated *xlrec = (xl_heap_lock_updated *) rec;
- appendStringInfo(buf, "lock updated: xmax %u msk %04x; ", xlrec->xmax,
+ appendStringInfo(buf, "xmax %u msk %04x; ", xlrec->xmax,
xlrec->infobits_set);
out_target(buf, &(xlrec->target));
}
@@ -185,11 +160,91 @@ heap2_desc(StringInfo buf, XLogRecord *record)
{
xl_heap_new_cid *xlrec = (xl_heap_new_cid *) rec;
- appendStringInfo(buf, "new_cid: ");
out_target(buf, &(xlrec->target));
appendStringInfo(buf, "; cmin: %u, cmax: %u, combo: %u",
xlrec->cmin, xlrec->cmax, xlrec->combocid);
}
- else
- appendStringInfoString(buf, "UNKNOWN");
+}
+
+static const char *
+append_init(const char *str)
+{
+ static char x[32];
+
+ strcpy(x, str);
+ strcat(x, "+INIT");
+
+ return x;
+}
+
+const char *
+heap_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info & XLOG_HEAP_OPMASK)
+ {
+ case XLOG_HEAP_INSERT:
+ id = "INSERT";
+ break;
+ case XLOG_HEAP_DELETE:
+ id = "DELETE";
+ break;
+ case XLOG_HEAP_UPDATE:
+ id = "UPDATE";
+ break;
+ case XLOG_HEAP_HOT_UPDATE:
+ id = "HOT_UPDATE";
+ break;
+ case XLOG_HEAP_LOCK:
+ id = "LOCK";
+ break;
+ case XLOG_HEAP_INPLACE:
+ id = "INPLACE";
+ break;
+ }
+
+ if (info & XLOG_HEAP_INIT_PAGE)
+ id = append_init(id);
+
+ return id;
+}
+
+const char *
+heap2_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info & XLOG_HEAP_OPMASK)
+ {
+ case XLOG_HEAP2_CLEAN:
+ id = "CLEAN";
+ break;
+ case XLOG_HEAP2_FREEZE_PAGE:
+ id = "FREEZE_PAGE";
+ break;
+ case XLOG_HEAP2_CLEANUP_INFO:
+ id = "CLEANUP_INFO";
+ break;
+ case XLOG_HEAP2_VISIBLE:
+ id = "VISIBLE";
+ break;
+ case XLOG_HEAP2_MULTI_INSERT:
+ id = "MULTI_INSERT";
+ break;
+ case XLOG_HEAP2_LOCK_UPDATED:
+ id = "LOCK_UPDATED";
+ break;
+ case XLOG_HEAP2_NEW_CID:
+ id = "NEW_CID";
+ break;
+ case XLOG_HEAP2_REWRITE:
+ id = "REWRITE";
+ break;
+ }
+
+ if (info & XLOG_HEAP_INIT_PAGE)
+ id = append_init(id);
+
+ return id;
}
diff --git a/src/backend/access/rmgrdesc/mxactdesc.c b/src/backend/access/rmgrdesc/mxactdesc.c
index 50d9b55..177aebe 100644
--- a/src/backend/access/rmgrdesc/mxactdesc.c
+++ b/src/backend/access/rmgrdesc/mxactdesc.c
@@ -52,30 +52,43 @@ multixact_desc(StringInfo buf, XLogRecord *record)
char *rec = XLogRecGetData(record);
uint8 info = record->xl_info & ~XLR_INFO_MASK;
- if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
+ if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE ||
+ info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
{
int pageno;
memcpy(&pageno, rec, sizeof(int));
- appendStringInfo(buf, "zero offsets page: %d", pageno);
- }
- else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
- {
- int pageno;
-
- memcpy(&pageno, rec, sizeof(int));
- appendStringInfo(buf, "zero members page: %d", pageno);
+ appendStringInfo(buf, "%d", pageno);
}
else if (info == XLOG_MULTIXACT_CREATE_ID)
{
xl_multixact_create *xlrec = (xl_multixact_create *) rec;
int i;
- appendStringInfo(buf, "create mxid %u offset %u nmembers %d: ", xlrec->mid,
+ appendStringInfo(buf, "%u offset %u nmembers %d: ", xlrec->mid,
xlrec->moff, xlrec->nmembers);
for (i = 0; i < xlrec->nmembers; i++)
out_member(buf, &xlrec->members[i]);
}
- else
- appendStringInfoString(buf, "UNKNOWN");
+}
+
+const char *
+multixact_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_MULTIXACT_ZERO_OFF_PAGE:
+ id = "ZERO_OFF_PAGE";
+ break;
+ case XLOG_MULTIXACT_ZERO_MEM_PAGE:
+ id = "ZERO_MEM_PAGE";
+ break;
+ case XLOG_MULTIXACT_CREATE_ID:
+ id = "CREATE_ID";
+ break;
+ }
+
+ return id;
}
diff --git a/src/backend/access/rmgrdesc/nbtdesc.c b/src/backend/access/rmgrdesc/nbtdesc.c
index bf3389c..7eb3bbd 100644
--- a/src/backend/access/rmgrdesc/nbtdesc.c
+++ b/src/backend/access/rmgrdesc/nbtdesc.c
@@ -34,74 +34,26 @@ btree_desc(StringInfo buf, XLogRecord *record)
switch (info)
{
case XLOG_BTREE_INSERT_LEAF:
- {
- xl_btree_insert *xlrec = (xl_btree_insert *) rec;
-
- appendStringInfoString(buf, "insert: ");
- out_target(buf, &(xlrec->target));
- break;
- }
case XLOG_BTREE_INSERT_UPPER:
- {
- xl_btree_insert *xlrec = (xl_btree_insert *) rec;
-
- appendStringInfoString(buf, "insert_upper: ");
- out_target(buf, &(xlrec->target));
- break;
- }
case XLOG_BTREE_INSERT_META:
{
xl_btree_insert *xlrec = (xl_btree_insert *) rec;
- appendStringInfoString(buf, "insert_meta: ");
out_target(buf, &(xlrec->target));
break;
}
case XLOG_BTREE_SPLIT_L:
- {
- xl_btree_split *xlrec = (xl_btree_split *) rec;
-
- appendStringInfo(buf, "split_l: rel %u/%u/%u ",
- xlrec->node.spcNode, xlrec->node.dbNode,
- xlrec->node.relNode);
- appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
- xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
- xlrec->level, xlrec->firstright);
- break;
- }
case XLOG_BTREE_SPLIT_R:
- {
- xl_btree_split *xlrec = (xl_btree_split *) rec;
-
- appendStringInfo(buf, "split_r: rel %u/%u/%u ",
- xlrec->node.spcNode, xlrec->node.dbNode,
- xlrec->node.relNode);
- appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
- xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
- xlrec->level, xlrec->firstright);
- break;
- }
case XLOG_BTREE_SPLIT_L_ROOT:
- {
- xl_btree_split *xlrec = (xl_btree_split *) rec;
-
- appendStringInfo(buf, "split_l_root: rel %u/%u/%u ",
- xlrec->node.spcNode, xlrec->node.dbNode,
- xlrec->node.relNode);
- appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
- xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
- xlrec->level, xlrec->firstright);
- break;
- }
case XLOG_BTREE_SPLIT_R_ROOT:
{
xl_btree_split *xlrec = (xl_btree_split *) rec;
- appendStringInfo(buf, "split_r_root: rel %u/%u/%u ",
+ appendStringInfo(buf, "rel %u/%u/%u ",
xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->node.relNode);
appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
- xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
+ xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
xlrec->level, xlrec->firstright);
break;
}
@@ -109,7 +61,7 @@ btree_desc(StringInfo buf, XLogRecord *record)
{
xl_btree_vacuum *xlrec = (xl_btree_vacuum *) rec;
- appendStringInfo(buf, "vacuum: rel %u/%u/%u; blk %u, lastBlockVacuumed %u",
+ appendStringInfo(buf, "rel %u/%u/%u; blk %u, lastBlockVacuumed %u",
xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->node.relNode, xlrec->block,
xlrec->lastBlockVacuumed);
@@ -119,8 +71,8 @@ btree_desc(StringInfo buf, XLogRecord *record)
{
xl_btree_delete *xlrec = (xl_btree_delete *) rec;
- appendStringInfo(buf, "delete: index %u/%u/%u; iblk %u, heap %u/%u/%u;",
- xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
+ appendStringInfo(buf, "index %u/%u/%u; iblk %u, heap %u/%u/%u;",
+ xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
xlrec->block,
xlrec->hnode.spcNode, xlrec->hnode.dbNode, xlrec->hnode.relNode);
break;
@@ -129,7 +81,6 @@ btree_desc(StringInfo buf, XLogRecord *record)
{
xl_btree_mark_page_halfdead *xlrec = (xl_btree_mark_page_halfdead *) rec;
- appendStringInfoString(buf, "mark_page_halfdead: ");
out_target(buf, &(xlrec->target));
appendStringInfo(buf, "; topparent %u; leaf %u; left %u; right %u",
xlrec->topparent, xlrec->leafblk, xlrec->leftblk, xlrec->rightblk);
@@ -140,8 +91,8 @@ btree_desc(StringInfo buf, XLogRecord *record)
{
xl_btree_unlink_page *xlrec = (xl_btree_unlink_page *) rec;
- appendStringInfo(buf, "unlink_page: rel %u/%u/%u; ",
- xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
+ appendStringInfo(buf, "rel %u/%u/%u; ",
+ xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
appendStringInfo(buf, "dead %u; left %u; right %u; btpo_xact %u; ",
xlrec->deadblk, xlrec->leftsib, xlrec->rightsib, xlrec->btpo_xact);
appendStringInfo(buf, "leaf %u; leafleft %u; leafright %u; topparent %u",
@@ -152,7 +103,7 @@ btree_desc(StringInfo buf, XLogRecord *record)
{
xl_btree_newroot *xlrec = (xl_btree_newroot *) rec;
- appendStringInfo(buf, "newroot: rel %u/%u/%u; root %u lev %u",
+ appendStringInfo(buf, "rel %u/%u/%u; root %u lev %u",
xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->node.relNode,
xlrec->rootblk, xlrec->level);
@@ -162,13 +113,64 @@ btree_desc(StringInfo buf, XLogRecord *record)
{
xl_btree_reuse_page *xlrec = (xl_btree_reuse_page *) rec;
- appendStringInfo(buf, "reuse_page: rel %u/%u/%u; latestRemovedXid %u",
+ appendStringInfo(buf, "rel %u/%u/%u; latestRemovedXid %u",
xlrec->node.spcNode, xlrec->node.dbNode,
- xlrec->node.relNode, xlrec->latestRemovedXid);
+ xlrec->node.relNode, xlrec->latestRemovedXid);
break;
}
- default:
- appendStringInfoString(buf, "UNKNOWN");
+ }
+}
+
+const char *
+btree_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_BTREE_INSERT_LEAF:
+ id = "INSERT_LEAF";
+ break;
+ case XLOG_BTREE_INSERT_UPPER:
+ id = "INSERT_UPPER";
+ break;
+ case XLOG_BTREE_INSERT_META:
+ id = "INSERT_META";
+ break;
+ case XLOG_BTREE_SPLIT_L:
+ id = "SPLIT_L";
+ break;
+ case XLOG_BTREE_SPLIT_R:
+ id = "SPLIT_R";
+ break;
+ case XLOG_BTREE_SPLIT_L_ROOT:
+ id = "SPLIT_L_ROOT";
+ break;
+ case XLOG_BTREE_SPLIT_R_ROOT:
+ id = "SPLIT_R_ROOT";
+ break;
+ case XLOG_BTREE_VACUUM:
+ id = "VACUUM";
+ break;
+ case XLOG_BTREE_DELETE:
+ id = "DELETE";
+ break;
+ case XLOG_BTREE_MARK_PAGE_HALFDEAD:
+ id = "MARK_PAGE_HALFDEAD";
+ break;
+ case XLOG_BTREE_UNLINK_PAGE:
+ id = "UNLINK_PAGE";
+ break;
+ case XLOG_BTREE_UNLINK_PAGE_META:
+ id = "UNLINK_PAGE_META";
+ break;
+ case XLOG_BTREE_NEWROOT:
+ id = "NEWROOT";
+ break;
+ case XLOG_BTREE_REUSE_PAGE:
+ id = "REUSE_PAGE";
break;
}
+
+ return id;
}
diff --git a/src/backend/access/rmgrdesc/relmapdesc.c b/src/backend/access/rmgrdesc/relmapdesc.c
index 06fd4b3..39dcfb5 100644
--- a/src/backend/access/rmgrdesc/relmapdesc.c
+++ b/src/backend/access/rmgrdesc/relmapdesc.c
@@ -26,9 +26,22 @@ relmap_desc(StringInfo buf, XLogRecord *record)
{
xl_relmap_update *xlrec = (xl_relmap_update *) rec;
- appendStringInfo(buf, "update relmap: database %u tablespace %u size %u",
+ appendStringInfo(buf, "database %u tablespace %u size %u",
xlrec->dbid, xlrec->tsid, xlrec->nbytes);
}
- else
- appendStringInfoString(buf, "UNKNOWN");
+}
+
+const char *
+relmap_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_RELMAP_UPDATE:
+ id = "UPDATE";
+ break;
+ }
+
+ return id;
}
diff --git a/src/backend/access/rmgrdesc/seqdesc.c b/src/backend/access/rmgrdesc/seqdesc.c
index 42eb9b9..d44fe62 100644
--- a/src/backend/access/rmgrdesc/seqdesc.c
+++ b/src/backend/access/rmgrdesc/seqdesc.c
@@ -25,13 +25,22 @@ seq_desc(StringInfo buf, XLogRecord *record)
xl_seq_rec *xlrec = (xl_seq_rec *) rec;
if (info == XLOG_SEQ_LOG)
- appendStringInfoString(buf, "log: ");
- else
+ appendStringInfo(buf, "rel %u/%u/%u",
+ xlrec->node.spcNode, xlrec->node.dbNode,
+ xlrec->node.relNode);
+}
+
+const char *
+seq_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
{
- appendStringInfoString(buf, "UNKNOWN");
- return;
+ case XLOG_SEQ_LOG:
+ id = "LOG";
+ break;
}
- appendStringInfo(buf, "rel %u/%u/%u",
- xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
+ return id;
}
diff --git a/src/backend/access/rmgrdesc/smgrdesc.c b/src/backend/access/rmgrdesc/smgrdesc.c
index c76c815..ee711bc 100644
--- a/src/backend/access/rmgrdesc/smgrdesc.c
+++ b/src/backend/access/rmgrdesc/smgrdesc.c
@@ -29,7 +29,7 @@ smgr_desc(StringInfo buf, XLogRecord *record)
xl_smgr_create *xlrec = (xl_smgr_create *) rec;
char *path = relpathperm(xlrec->rnode, xlrec->forkNum);
- appendStringInfo(buf, "file create: %s", path);
+ appendStringInfo(buf, "%s", path);
pfree(path);
}
else if (info == XLOG_SMGR_TRUNCATE)
@@ -37,10 +37,25 @@ smgr_desc(StringInfo buf, XLogRecord *record)
xl_smgr_truncate *xlrec = (xl_smgr_truncate *) rec;
char *path = relpathperm(xlrec->rnode, MAIN_FORKNUM);
- appendStringInfo(buf, "file truncate: %s to %u blocks", path,
- xlrec->blkno);
+ appendStringInfo(buf, "%s to %u blocks", path, xlrec->blkno);
pfree(path);
}
- else
- appendStringInfoString(buf, "UNKNOWN");
+}
+
+const char *
+smgr_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_SMGR_CREATE:
+ id = "CREATE";
+ break;
+ case XLOG_SMGR_TRUNCATE:
+ id = "TRUNCATE";
+ break;
+ }
+
+ return id;
}
diff --git a/src/backend/access/rmgrdesc/spgdesc.c b/src/backend/access/rmgrdesc/spgdesc.c
index ed369b2..74b2177 100644
--- a/src/backend/access/rmgrdesc/spgdesc.c
+++ b/src/backend/access/rmgrdesc/spgdesc.c
@@ -32,32 +32,32 @@ spg_desc(StringInfo buf, XLogRecord *record)
switch (info)
{
case XLOG_SPGIST_CREATE_INDEX:
- appendStringInfo(buf, "create_index: rel %u/%u/%u",
+ appendStringInfo(buf, "rel %u/%u/%u",
((RelFileNode *) rec)->spcNode,
((RelFileNode *) rec)->dbNode,
((RelFileNode *) rec)->relNode);
break;
case XLOG_SPGIST_ADD_LEAF:
out_target(buf, ((spgxlogAddLeaf *) rec)->node);
- appendStringInfo(buf, "add leaf to page: %u",
+ appendStringInfo(buf, "%u",
((spgxlogAddLeaf *) rec)->blknoLeaf);
break;
case XLOG_SPGIST_MOVE_LEAFS:
out_target(buf, ((spgxlogMoveLeafs *) rec)->node);
- appendStringInfo(buf, "move %u leafs from page %u to page %u",
+ appendStringInfo(buf, "%u leafs from page %u to page %u",
((spgxlogMoveLeafs *) rec)->nMoves,
((spgxlogMoveLeafs *) rec)->blknoSrc,
((spgxlogMoveLeafs *) rec)->blknoDst);
break;
case XLOG_SPGIST_ADD_NODE:
out_target(buf, ((spgxlogAddNode *) rec)->node);
- appendStringInfo(buf, "add node to %u:%u",
+ appendStringInfo(buf, "%u:%u",
((spgxlogAddNode *) rec)->blkno,
((spgxlogAddNode *) rec)->offnum);
break;
case XLOG_SPGIST_SPLIT_TUPLE:
out_target(buf, ((spgxlogSplitTuple *) rec)->node);
- appendStringInfo(buf, "split node %u:%u to %u:%u",
+ appendStringInfo(buf, "%u:%u to %u:%u",
((spgxlogSplitTuple *) rec)->blknoPrefix,
((spgxlogSplitTuple *) rec)->offnumPrefix,
((spgxlogSplitTuple *) rec)->blknoPostfix,
@@ -65,26 +65,61 @@ spg_desc(StringInfo buf, XLogRecord *record)
break;
case XLOG_SPGIST_PICKSPLIT:
out_target(buf, ((spgxlogPickSplit *) rec)->node);
- appendStringInfoString(buf, "split leaf page");
break;
case XLOG_SPGIST_VACUUM_LEAF:
out_target(buf, ((spgxlogVacuumLeaf *) rec)->node);
- appendStringInfo(buf, "vacuum leaf tuples on page %u",
+ appendStringInfo(buf, "page %u",
((spgxlogVacuumLeaf *) rec)->blkno);
break;
case XLOG_SPGIST_VACUUM_ROOT:
out_target(buf, ((spgxlogVacuumRoot *) rec)->node);
- appendStringInfo(buf, "vacuum leaf tuples on root page %u",
+ appendStringInfo(buf, "page %u",
((spgxlogVacuumRoot *) rec)->blkno);
break;
case XLOG_SPGIST_VACUUM_REDIRECT:
out_target(buf, ((spgxlogVacuumRedirect *) rec)->node);
- appendStringInfo(buf, "vacuum redirect tuples on page %u, newest XID %u",
+ appendStringInfo(buf, "page %u, newest XID %u",
((spgxlogVacuumRedirect *) rec)->blkno,
- ((spgxlogVacuumRedirect *) rec)->newestRedirectXid);
+ ((spgxlogVacuumRedirect *) rec)->newestRedirectXid);
break;
- default:
- appendStringInfo(buf, "unknown spgist op code %u", info);
+ }
+}
+
+const char *
+spg_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_SPGIST_CREATE_INDEX:
+ id = "CREATE_INDEX";
+ break;
+ case XLOG_SPGIST_ADD_LEAF:
+ id = "ADD_LEAF";
+ break;
+ case XLOG_SPGIST_MOVE_LEAFS:
+ id = "MOVE_LEAFS";
+ break;
+ case XLOG_SPGIST_ADD_NODE:
+ id = "ADD_NODE";
+ break;
+ case XLOG_SPGIST_SPLIT_TUPLE:
+ id = "SPLIT_TUPLE";
+ break;
+ case XLOG_SPGIST_PICKSPLIT:
+ id = "PICKSPLIT";
+ break;
+ case XLOG_SPGIST_VACUUM_LEAF:
+ id = "VACUUM_LEAF";
+ break;
+ case XLOG_SPGIST_VACUUM_ROOT:
+ id = "VACUUM_ROOT";
+ break;
+ case XLOG_SPGIST_VACUUM_REDIRECT:
+ id = "VACUUM_REDIRECT";
break;
}
+
+ return id;
}
diff --git a/src/backend/access/rmgrdesc/standbydesc.c b/src/backend/access/rmgrdesc/standbydesc.c
index a127d38..436b27c 100644
--- a/src/backend/access/rmgrdesc/standbydesc.c
+++ b/src/backend/access/rmgrdesc/standbydesc.c
@@ -47,10 +47,8 @@ standby_desc(StringInfo buf, XLogRecord *record)
xl_standby_locks *xlrec = (xl_standby_locks *) rec;
int i;
- appendStringInfoString(buf, "AccessExclusive locks:");
-
for (i = 0; i < xlrec->nlocks; i++)
- appendStringInfo(buf, " xid %u db %u rel %u",
+ appendStringInfo(buf, "xid %u db %u rel %u ",
xlrec->locks[i].xid, xlrec->locks[i].dbOid,
xlrec->locks[i].relOid);
}
@@ -58,9 +56,24 @@ standby_desc(StringInfo buf, XLogRecord *record)
{
xl_running_xacts *xlrec = (xl_running_xacts *) rec;
- appendStringInfoString(buf, "running xacts:");
standby_desc_running_xacts(buf, xlrec);
}
- else
- appendStringInfoString(buf, "UNKNOWN");
+}
+
+const char *
+standby_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_STANDBY_LOCK:
+ id = "LOCK";
+ break;
+ case XLOG_RUNNING_XACTS:
+ id = "RUNNING_XACTS";
+ break;
+ }
+
+ return id;
}
diff --git a/src/backend/access/rmgrdesc/tblspcdesc.c b/src/backend/access/rmgrdesc/tblspcdesc.c
index 30b1f06..effeaf6 100644
--- a/src/backend/access/rmgrdesc/tblspcdesc.c
+++ b/src/backend/access/rmgrdesc/tblspcdesc.c
@@ -27,15 +27,30 @@ tblspc_desc(StringInfo buf, XLogRecord *record)
{
xl_tblspc_create_rec *xlrec = (xl_tblspc_create_rec *) rec;
- appendStringInfo(buf, "create tablespace: %u \"%s\"",
- xlrec->ts_id, xlrec->ts_path);
+ appendStringInfo(buf, "%u \"%s\"", xlrec->ts_id, xlrec->ts_path);
}
else if (info == XLOG_TBLSPC_DROP)
{
xl_tblspc_drop_rec *xlrec = (xl_tblspc_drop_rec *) rec;
- appendStringInfo(buf, "drop tablespace: %u", xlrec->ts_id);
+ appendStringInfo(buf, "%u", xlrec->ts_id);
}
- else
- appendStringInfoString(buf, "UNKNOWN");
+}
+
+const char *
+tblspc_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_TBLSPC_CREATE:
+ id = "CREATE";
+ break;
+ case XLOG_TBLSPC_DROP:
+ id = "DROP";
+ break;
+ }
+
+ return id;
}
diff --git a/src/backend/access/rmgrdesc/xactdesc.c b/src/backend/access/rmgrdesc/xactdesc.c
index 994931e..11e64af 100644
--- a/src/backend/access/rmgrdesc/xactdesc.c
+++ b/src/backend/access/rmgrdesc/xactdesc.c
@@ -146,39 +146,32 @@ xact_desc(StringInfo buf, XLogRecord *record)
{
xl_xact_commit_compact *xlrec = (xl_xact_commit_compact *) rec;
- appendStringInfoString(buf, "commit: ");
xact_desc_commit_compact(buf, xlrec);
}
else if (info == XLOG_XACT_COMMIT)
{
xl_xact_commit *xlrec = (xl_xact_commit *) rec;
- appendStringInfoString(buf, "commit: ");
xact_desc_commit(buf, xlrec);
}
else if (info == XLOG_XACT_ABORT)
{
xl_xact_abort *xlrec = (xl_xact_abort *) rec;
- appendStringInfoString(buf, "abort: ");
xact_desc_abort(buf, xlrec);
}
- else if (info == XLOG_XACT_PREPARE)
- {
- appendStringInfoString(buf, "prepare");
- }
else if (info == XLOG_XACT_COMMIT_PREPARED)
{
xl_xact_commit_prepared *xlrec = (xl_xact_commit_prepared *) rec;
- appendStringInfo(buf, "commit prepared %u: ", xlrec->xid);
+ appendStringInfo(buf, "%u: ", xlrec->xid);
xact_desc_commit(buf, &xlrec->crec);
}
else if (info == XLOG_XACT_ABORT_PREPARED)
{
xl_xact_abort_prepared *xlrec = (xl_xact_abort_prepared *) rec;
- appendStringInfo(buf, "abort prepared %u: ", xlrec->xid);
+ appendStringInfo(buf, "%u: ", xlrec->xid);
xact_desc_abort(buf, &xlrec->arec);
}
else if (info == XLOG_XACT_ASSIGNMENT)
@@ -190,9 +183,40 @@ xact_desc(StringInfo buf, XLogRecord *record)
* interested in the top-level xid that issued the record and which
* xids are being reported here.
*/
- appendStringInfo(buf, "xid assignment xtop %u: ", xlrec->xtop);
+ appendStringInfo(buf, "xtop %u: ", xlrec->xtop);
xact_desc_assignment(buf, xlrec);
}
- else
- appendStringInfoString(buf, "UNKNOWN");
+}
+
+const char *
+xact_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_XACT_COMMIT:
+ id = "COMMIT";
+ break;
+ case XLOG_XACT_PREPARE:
+ id = "PREPARE";
+ break;
+ case XLOG_XACT_ABORT:
+ id = "ABORT";
+ break;
+ case XLOG_XACT_COMMIT_PREPARED:
+ id = "COMMIT_PREPARED";
+ break;
+ case XLOG_XACT_ABORT_PREPARED:
+ id = "ABORT_PREPARED";
+ break;
+ case XLOG_XACT_ASSIGNMENT:
+ id = "ASSIGNMENT";
+ break;
+ case XLOG_XACT_COMMIT_COMPACT:
+ id = "COMMIT_COMPACT";
+ break;
+ }
+
+ return id;
}
diff --git a/src/backend/access/rmgrdesc/xlogdesc.c b/src/backend/access/rmgrdesc/xlogdesc.c
index 2224da1..cdefaf5 100644
--- a/src/backend/access/rmgrdesc/xlogdesc.c
+++ b/src/backend/access/rmgrdesc/xlogdesc.c
@@ -42,7 +42,7 @@ xlog_desc(StringInfo buf, XLogRecord *record)
{
CheckPoint *checkpoint = (CheckPoint *) rec;
- appendStringInfo(buf, "checkpoint: redo %X/%X; "
+ appendStringInfo(buf, "redo %X/%X; "
"tli %u; prev tli %u; fpw %s; xid %u/%u; oid %u; multi %u; offset %u; "
"oldest xid %u in DB %u; oldest multi %u in DB %u; "
"oldest running xid %u; %s",
@@ -61,33 +61,24 @@ xlog_desc(StringInfo buf, XLogRecord *record)
checkpoint->oldestActiveXid,
(info == XLOG_CHECKPOINT_SHUTDOWN) ? "shutdown" : "online");
}
- else if (info == XLOG_NOOP)
- {
- appendStringInfoString(buf, "xlog no-op");
- }
else if (info == XLOG_NEXTOID)
{
Oid nextOid;
memcpy(&nextOid, rec, sizeof(Oid));
- appendStringInfo(buf, "nextOid: %u", nextOid);
- }
- else if (info == XLOG_SWITCH)
- {
- appendStringInfoString(buf, "xlog switch");
+ appendStringInfo(buf, "%u", nextOid);
}
else if (info == XLOG_RESTORE_POINT)
{
xl_restore_point *xlrec = (xl_restore_point *) rec;
- appendStringInfo(buf, "restore point: %s", xlrec->rp_name);
-
+ appendStringInfo(buf, "%s", xlrec->rp_name);
}
else if (info == XLOG_FPI)
{
BkpBlock *bkp = (BkpBlock *) rec;
- appendStringInfo(buf, "full-page image: %s block %u",
+ appendStringInfo(buf, "%s block %u",
relpathperm(bkp->node, bkp->fork),
bkp->block);
}
@@ -96,7 +87,7 @@ xlog_desc(StringInfo buf, XLogRecord *record)
XLogRecPtr startpoint;
memcpy(&startpoint, rec, sizeof(XLogRecPtr));
- appendStringInfo(buf, "backup end: %X/%X",
+ appendStringInfo(buf, "%X/%X",
(uint32) (startpoint >> 32), (uint32) startpoint);
}
else if (info == XLOG_PARAMETER_CHANGE)
@@ -118,7 +109,7 @@ xlog_desc(StringInfo buf, XLogRecord *record)
}
}
- appendStringInfo(buf, "parameter change: max_connections=%d max_worker_processes=%d max_prepared_xacts=%d max_locks_per_xact=%d wal_level=%s",
+ appendStringInfo(buf, "max_connections=%d max_worker_processes=%d max_prepared_xacts=%d max_locks_per_xact=%d wal_level=%s",
xlrec.MaxConnections,
xlrec.max_worker_processes,
xlrec.max_prepared_xacts,
@@ -130,17 +121,60 @@ xlog_desc(StringInfo buf, XLogRecord *record)
bool fpw;
memcpy(&fpw, rec, sizeof(bool));
- appendStringInfo(buf, "full_page_writes: %s", fpw ? "true" : "false");
+ appendStringInfo(buf, "%s", fpw ? "true" : "false");
}
else if (info == XLOG_END_OF_RECOVERY)
{
xl_end_of_recovery xlrec;
memcpy(&xlrec, rec, sizeof(xl_end_of_recovery));
- appendStringInfo(buf, "end_of_recovery: tli %u; prev tli %u; time %s",
+ appendStringInfo(buf, "tli %u; prev tli %u; time %s",
xlrec.ThisTimeLineID, xlrec.PrevTimeLineID,
timestamptz_to_str(xlrec.end_time));
}
- else
- appendStringInfoString(buf, "UNKNOWN");
+}
+
+const char *
+xlog_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_CHECKPOINT_SHUTDOWN:
+ id = "CHECKPOINT_SHUTDOWN";
+ break;
+ case XLOG_CHECKPOINT_ONLINE:
+ id = "CHECKPOINT_ONLINE";
+ break;
+ case XLOG_NOOP:
+ id = "NOOP";
+ break;
+ case XLOG_NEXTOID:
+ id = "NEXTOID";
+ break;
+ case XLOG_SWITCH:
+ id = "SWITCH";
+ break;
+ case XLOG_BACKUP_END:
+ id = "BACKUP_END";
+ break;
+ case XLOG_PARAMETER_CHANGE:
+ id = "PARAMETER_CHANGE";
+ break;
+ case XLOG_RESTORE_POINT:
+ id = "RESTORE_POINT";
+ break;
+ case XLOG_FPW_CHANGE:
+ id = "FPW_CHANGE";
+ break;
+ case XLOG_END_OF_RECOVERY:
+ id = "END_OF_RECOVERY";
+ break;
+ case XLOG_FPI:
+ id = "FPI";
+ break;
+ }
+
+ return id;
}
diff --git a/src/backend/access/transam/rmgr.c b/src/backend/access/transam/rmgr.c
index c0a7a6f..2645a7a 100644
--- a/src/backend/access/transam/rmgr.c
+++ b/src/backend/access/transam/rmgr.c
@@ -25,8 +25,8 @@
#include "utils/relmapper.h"
/* must be kept in sync with RmgrData definition in xlog_internal.h */
-#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \
- { name, redo, desc, startup, cleanup },
+#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \
+ { name, redo, desc, identify, startup, cleanup },
const RmgrData RmgrTable[RM_MAX_ID + 1] = {
#include "access/rmgrlist.h"
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 34f2fc0..6335db5 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -799,6 +799,7 @@ static bool CheckForStandbyTrigger(void);
#ifdef WAL_DEBUG
static void xlog_outrec(StringInfo buf, XLogRecord *record);
#endif
+static void xlog_outdesc(StringInfo buf, RmgrId rmid, XLogRecord *record);
static void pg_start_backup_callback(int code, Datum arg);
static bool read_backup_label(XLogRecPtr *checkPointLoc,
bool *backupEndRequired, bool *backupFromStandby);
@@ -1286,8 +1287,8 @@ begin:;
for (; rdata != NULL; rdata = rdata->next)
appendBinaryStringInfo(&recordbuf, rdata->data, rdata->len);
- appendStringInfoString(&buf, " - ");
- RmgrTable[rechdr->xl_rmid].rm_desc(&buf, (XLogRecord *) recordbuf.data);
+ appendStringInfoString(&buf, ": ");
+ xlog_outdesc(&buf, rechdr->xl_rmid, (XLogRecord *) recordbuf.data);
}
elog(LOG, "%s", buf.data);
@@ -6709,8 +6710,8 @@ StartupXLOG(void)
(uint32) (ReadRecPtr >> 32), (uint32) ReadRecPtr,
(uint32) (EndRecPtr >> 32), (uint32) EndRecPtr);
xlog_outrec(&buf, record);
- appendStringInfoString(&buf, " - ");
- RmgrTable[record->xl_rmid].rm_desc(&buf, record);
+ appendStringInfoString(&buf, ": ");
+ xlog_outdesc(&buf, record->xl_rmid, record);
elog(LOG, "%s", buf.data);
pfree(buf.data);
}
@@ -9624,11 +9625,41 @@ xlog_outrec(StringInfo buf, XLogRecord *record)
if (record->xl_info & XLR_BKP_BLOCK(i))
appendStringInfo(buf, "; bkpb%d", i);
}
-
- appendStringInfo(buf, ": %s", RmgrTable[record->xl_rmid].rm_name);
}
#endif /* WAL_DEBUG */
+/*
+ * Returns a string describing an XLogRecord, consisting of its identity
+ * optionally followed by a colon, a space, and a further description.
+ */
+static void
+xlog_outdesc(StringInfo buf, RmgrId rmid, XLogRecord *record)
+{
+ const char *id;
+
+ appendStringInfoString(buf, RmgrTable[rmid].rm_name);
+ appendStringInfoChar(buf, '/');
+
+ id = RmgrTable[rmid].rm_identify(record->xl_info);
+ if (id == NULL)
+ appendStringInfo(buf, "UNKNOWN (%X)", record->xl_info);
+ else
+ {
+ StringInfoData desc;
+
+ initStringInfo(&desc);
+ RmgrTable[rmid].rm_desc(&desc, record);
+
+ appendStringInfoString(buf, id);
+ if (desc.len > 0)
+ {
+ appendStringInfoString(buf, ": ");
+ appendStringInfoString(buf, desc.data);
+ pfree(desc.data);
+ }
+ }
+}
+
/*
* Return the (possible) sync flag used for opening a file, depending on the
@@ -10664,7 +10695,7 @@ rm_redo_error_callback(void *arg)
StringInfoData buf;
initStringInfo(&buf);
- RmgrTable[record->xl_rmid].rm_desc(&buf, record);
+ xlog_outdesc(&buf, record->xl_rmid, record);
/* don't bother emitting empty description */
if (buf.len > 0)
diff --git a/src/include/access/clog.h b/src/include/access/clog.h
index be9b867..8562631 100644
--- a/src/include/access/clog.h
+++ b/src/include/access/clog.h
@@ -49,5 +49,6 @@ extern void TruncateCLOG(TransactionId oldestXact);
extern void clog_redo(XLogRecPtr lsn, XLogRecord *record);
extern void clog_desc(StringInfo buf, XLogRecord *record);
+extern const char *clog_identify(uint8 info);
#endif /* CLOG_H */
diff --git a/src/include/access/gin.h b/src/include/access/gin.h
index a0b288d..0ebecb4 100644
--- a/src/include/access/gin.h
+++ b/src/include/access/gin.h
@@ -74,6 +74,7 @@ extern void ginUpdateStats(Relation index, const GinStatsData *stats);
/* ginxlog.c */
extern void gin_redo(XLogRecPtr lsn, XLogRecord *record);
extern void gin_desc(StringInfo buf, XLogRecord *record);
+extern const char *gin_identify(uint8 info);
extern void gin_xlog_startup(void);
extern void gin_xlog_cleanup(void);
diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h
index 03e9903..879f113 100644
--- a/src/include/access/gist_private.h
+++ b/src/include/access/gist_private.h
@@ -452,6 +452,7 @@ extern SplitedPageLayout *gistSplit(Relation r, Page page, IndexTuple *itup,
/* gistxlog.c */
extern void gist_redo(XLogRecPtr lsn, XLogRecord *record);
extern void gist_desc(StringInfo buf, XLogRecord *record);
+extern const char *gist_identify(uint8 info);
extern void gist_xlog_startup(void);
extern void gist_xlog_cleanup(void);
diff --git a/src/include/access/hash.h b/src/include/access/hash.h
index ff29fea..a81b9de 100644
--- a/src/include/access/hash.h
+++ b/src/include/access/hash.h
@@ -357,5 +357,6 @@ extern OffsetNumber _hash_binsearch_last(Page page, uint32 hash_value);
/* hash.c */
extern void hash_redo(XLogRecPtr lsn, XLogRecord *record);
extern void hash_desc(StringInfo buf, XLogRecord *record);
+extern const char *hash_identify(uint8 info);
#endif /* HASH_H */
diff --git a/src/include/access/heapam_xlog.h b/src/include/access/heapam_xlog.h
index 2544347..5ac98a5 100644
--- a/src/include/access/heapam_xlog.h
+++ b/src/include/access/heapam_xlog.h
@@ -357,8 +357,10 @@ extern void HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple,
extern void heap_redo(XLogRecPtr lsn, XLogRecord *record);
extern void heap_desc(StringInfo buf, XLogRecord *record);
+extern const char *heap_identify(uint8 info);
extern void heap2_redo(XLogRecPtr lsn, XLogRecord *record);
extern void heap2_desc(StringInfo buf, XLogRecord *record);
+extern const char *heap2_identify(uint8 info);
extern void heap_xlog_logical_rewrite(XLogRecPtr lsn, XLogRecord *r);
extern XLogRecPtr log_heap_cleanup_info(RelFileNode rnode,
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index 8db773b..b331447 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -136,6 +136,7 @@ extern void multixact_twophase_postabort(TransactionId xid, uint16 info,
extern void multixact_redo(XLogRecPtr lsn, XLogRecord *record);
extern void multixact_desc(StringInfo buf, XLogRecord *record);
+extern const char *multixact_identify(uint8 info);
extern char *mxid_to_string(MultiXactId multi, int nmembers,
MultiXactMember *members);
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
index 9fa943f..90fd6d0 100644
--- a/src/include/access/nbtree.h
+++ b/src/include/access/nbtree.h
@@ -726,5 +726,6 @@ extern void _bt_leafbuild(BTSpool *btspool, BTSpool *spool2);
*/
extern void btree_redo(XLogRecPtr lsn, XLogRecord *record);
extern void btree_desc(StringInfo buf, XLogRecord *record);
+extern const char *btree_identify(uint8 info);
#endif /* NBTREE_H */
diff --git a/src/include/access/rmgr.h b/src/include/access/rmgr.h
index 1b577a2..ff7fe62 100644
--- a/src/include/access/rmgr.h
+++ b/src/include/access/rmgr.h
@@ -19,7 +19,7 @@ typedef uint8 RmgrId;
* Note: RM_MAX_ID must fit in RmgrId; widening that type will affect the XLOG
* file format.
*/
-#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \
+#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \
symname,
typedef enum RmgrIds
diff --git a/src/include/access/rmgrlist.h b/src/include/access/rmgrlist.h
index 662fb77..77d4574 100644
--- a/src/include/access/rmgrlist.h
+++ b/src/include/access/rmgrlist.h
@@ -25,20 +25,20 @@
*/
/* symbol name, textual name, redo, desc, startup, cleanup */
-PG_RMGR(RM_XLOG_ID, "XLOG", xlog_redo, xlog_desc, NULL, NULL)
-PG_RMGR(RM_XACT_ID, "Transaction", xact_redo, xact_desc, NULL, NULL)
-PG_RMGR(RM_SMGR_ID, "Storage", smgr_redo, smgr_desc, NULL, NULL)
-PG_RMGR(RM_CLOG_ID, "CLOG", clog_redo, clog_desc, NULL, NULL)
-PG_RMGR(RM_DBASE_ID, "Database", dbase_redo, dbase_desc, NULL, NULL)
-PG_RMGR(RM_TBLSPC_ID, "Tablespace", tblspc_redo, tblspc_desc, NULL, NULL)
-PG_RMGR(RM_MULTIXACT_ID, "MultiXact", multixact_redo, multixact_desc, NULL, NULL)
-PG_RMGR(RM_RELMAP_ID, "RelMap", relmap_redo, relmap_desc, NULL, NULL)
-PG_RMGR(RM_STANDBY_ID, "Standby", standby_redo, standby_desc, NULL, NULL)
-PG_RMGR(RM_HEAP2_ID, "Heap2", heap2_redo, heap2_desc, NULL, NULL)
-PG_RMGR(RM_HEAP_ID, "Heap", heap_redo, heap_desc, NULL, NULL)
-PG_RMGR(RM_BTREE_ID, "Btree", btree_redo, btree_desc, NULL, NULL)
-PG_RMGR(RM_HASH_ID, "Hash", hash_redo, hash_desc, NULL, NULL)
-PG_RMGR(RM_GIN_ID, "Gin", gin_redo, gin_desc, gin_xlog_startup, gin_xlog_cleanup)
-PG_RMGR(RM_GIST_ID, "Gist", gist_redo, gist_desc, gist_xlog_startup, gist_xlog_cleanup)
-PG_RMGR(RM_SEQ_ID, "Sequence", seq_redo, seq_desc, NULL, NULL)
-PG_RMGR(RM_SPGIST_ID, "SPGist", spg_redo, spg_desc, spg_xlog_startup, spg_xlog_cleanup)
+PG_RMGR(RM_XLOG_ID, "XLOG", xlog_redo, xlog_desc, xlog_identify, NULL, NULL)
+PG_RMGR(RM_XACT_ID, "Transaction", xact_redo, xact_desc, xact_identify, NULL, NULL)
+PG_RMGR(RM_SMGR_ID, "Storage", smgr_redo, smgr_desc, smgr_identify, NULL, NULL)
+PG_RMGR(RM_CLOG_ID, "CLOG", clog_redo, clog_desc, clog_identify, NULL, NULL)
+PG_RMGR(RM_DBASE_ID, "Database", dbase_redo, dbase_desc, dbase_identify, NULL, NULL)
+PG_RMGR(RM_TBLSPC_ID, "Tablespace", tblspc_redo, tblspc_desc, tblspc_identify, NULL, NULL)
+PG_RMGR(RM_MULTIXACT_ID, "MultiXact", multixact_redo, multixact_desc, multixact_identify, NULL, NULL)
+PG_RMGR(RM_RELMAP_ID, "RelMap", relmap_redo, relmap_desc, relmap_identify, NULL, NULL)
+PG_RMGR(RM_STANDBY_ID, "Standby", standby_redo, standby_desc, standby_identify, NULL, NULL)
+PG_RMGR(RM_HEAP2_ID, "Heap2", heap2_redo, heap2_desc, heap2_identify, NULL, NULL)
+PG_RMGR(RM_HEAP_ID, "Heap", heap_redo, heap_desc, heap_identify, NULL, NULL)
+PG_RMGR(RM_BTREE_ID, "Btree", btree_redo, btree_desc, btree_identify, NULL, NULL)
+PG_RMGR(RM_HASH_ID, "Hash", hash_redo, hash_desc, hash_identify, NULL, NULL)
+PG_RMGR(RM_GIN_ID, "Gin", gin_redo, gin_desc, gin_identify, gin_xlog_startup, gin_xlog_cleanup)
+PG_RMGR(RM_GIST_ID, "Gist", gist_redo, gist_desc, gist_identify, gist_xlog_startup, gist_xlog_cleanup)
+PG_RMGR(RM_SEQ_ID, "Sequence", seq_redo, seq_desc, seq_identify, NULL, NULL)
+PG_RMGR(RM_SPGIST_ID, "SPGist", spg_redo, spg_desc, spg_identify, spg_xlog_startup, spg_xlog_cleanup)
diff --git a/src/include/access/spgist.h b/src/include/access/spgist.h
index 7f8655c..f218a83 100644
--- a/src/include/access/spgist.h
+++ b/src/include/access/spgist.h
@@ -198,6 +198,7 @@ extern Datum spgvacuumcleanup(PG_FUNCTION_ARGS);
/* spgxlog.c */
extern void spg_redo(XLogRecPtr lsn, XLogRecord *record);
extern void spg_desc(StringInfo buf, XLogRecord *record);
+extern const char *spg_identify(uint8 info);
extern void spg_xlog_startup(void);
extern void spg_xlog_cleanup(void);
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 2168dc3..45376b4 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -256,5 +256,6 @@ extern int xactGetCommittedChildren(TransactionId **ptr);
extern void xact_redo(XLogRecPtr lsn, XLogRecord *record);
extern void xact_desc(StringInfo buf, XLogRecord *record);
+extern const char *xact_identify(uint8 info);
#endif /* XACT_H */
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 7d6db49..0b7bfa5 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -304,6 +304,7 @@ extern Buffer RestoreBackupBlock(XLogRecPtr lsn, XLogRecord *record,
extern void xlog_redo(XLogRecPtr lsn, XLogRecord *record);
extern void xlog_desc(StringInfo buf, XLogRecord *record);
+extern const char *xlog_identify(uint8 info);
extern void issue_xlog_fsync(int fd, XLogSegNo segno);
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index 954114f..836cc7c 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -239,6 +239,16 @@ struct XLogRecord;
* This struct must be kept in sync with the PG_RMGR definition in
* rmgr.c.
*
+ * rm_identify must return a name for the record based on xl_info
+ * (without reference to the rmid). For example, XLOG_BTREE_VACUUM
+ * would be named "VACUUM". rm_desc can then be called to obtain
+ * additional detail for the record, if available (e.g. the last
+ * block).
+ *
+ * The return value from rm_identify is a pointer to a statically
+ * allocated buffer, and is therefore valid only until the next
+ * invocation of the callback.
+ *
* RmgrTable[] is indexed by RmgrId values (see rmgrlist.h).
*/
typedef struct RmgrData
@@ -246,6 +256,7 @@ typedef struct RmgrData
const char *rm_name;
void (*rm_redo) (XLogRecPtr lsn, struct XLogRecord *rptr);
void (*rm_desc) (StringInfo buf, struct XLogRecord *rptr);
+ const char *(*rm_identify) (uint8 info);
void (*rm_startup) (void);
void (*rm_cleanup) (void);
} RmgrData;
diff --git a/src/include/catalog/storage_xlog.h b/src/include/catalog/storage_xlog.h
index 7081c99..5fc7235 100644
--- a/src/include/catalog/storage_xlog.h
+++ b/src/include/catalog/storage_xlog.h
@@ -45,5 +45,6 @@ extern void log_smgrcreate(RelFileNode *rnode, ForkNumber forkNum);
extern void smgr_redo(XLogRecPtr lsn, XLogRecord *record);
extern void smgr_desc(StringInfo buf, XLogRecord *record);
+extern const char *smgr_identify(uint8 info);
#endif /* STORAGE_XLOG_H */
diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h
index c2380dc..811713f 100644
--- a/src/include/commands/dbcommands.h
+++ b/src/include/commands/dbcommands.h
@@ -64,6 +64,7 @@ extern char *get_database_name(Oid dbid);
extern void dbase_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void dbase_desc(StringInfo buf, XLogRecord *rptr);
+extern const char *dbase_identify(uint8 info);
extern void check_encoding_locale_matches(int encoding, const char *collate, const char *ctype);
diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h
index 8819c00..914d155 100644
--- a/src/include/commands/sequence.h
+++ b/src/include/commands/sequence.h
@@ -78,5 +78,6 @@ extern void ResetSequenceCaches(void);
extern void seq_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void seq_desc(StringInfo buf, XLogRecord *rptr);
+extern const char *seq_identify(uint8 info);
#endif /* SEQUENCE_H */
diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h
index d01ae8b..0f16f40 100644
--- a/src/include/commands/tablespace.h
+++ b/src/include/commands/tablespace.h
@@ -57,5 +57,6 @@ extern bool directory_is_empty(const char *path);
extern void tblspc_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void tblspc_desc(StringInfo buf, XLogRecord *rptr);
+extern const char *tblspc_identify(uint8 info);
#endif /* TABLESPACE_H */
diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h
index da22fd3..1c63af5 100644
--- a/src/include/storage/standby.h
+++ b/src/include/storage/standby.h
@@ -83,6 +83,7 @@ typedef struct xl_running_xacts
/* Recovery handlers for the Standby Rmgr (RM_STANDBY_ID) */
extern void standby_redo(XLogRecPtr lsn, XLogRecord *record);
extern void standby_desc(StringInfo buf, XLogRecord *record);
+extern const char *standby_identify(uint8 info);
/*
* Declarations for GetRunningTransactionData(). Similar to Snapshots, but
diff --git a/src/include/utils/relmapper.h b/src/include/utils/relmapper.h
index 76bcf18..37937dd 100644
--- a/src/include/utils/relmapper.h
+++ b/src/include/utils/relmapper.h
@@ -60,5 +60,6 @@ extern void RelationMapInitializePhase3(void);
extern void relmap_redo(XLogRecPtr lsn, XLogRecord *record);
extern void relmap_desc(StringInfo buf, XLogRecord *record);
+extern const char *relmap_identify(uint8 info);
#endif /* RELMAPPER_H */
--
1.9.1
0002-Make-pg_xlogdump-stats-record-display-summary-statis.patchtext/x-diff; charset=us-asciiDownload
>From c10148fac6a7eec517b024d8bd27b81552247817 Mon Sep 17 00:00:00 2001
From: Abhijit Menon-Sen <ams@2ndQuadrant.com>
Date: Wed, 4 Jun 2014 14:22:33 +0530
Subject: Make 'pg_xlogdump --stats[=record]' display summary statistics
---
contrib/pg_xlogdump/pg_xlogdump.c | 228 +++++++++++++++++++++++++++++++++++---
contrib/pg_xlogdump/rmgrdesc.c | 2 +-
contrib/pg_xlogdump/rmgrdesc.h | 1 +
doc/src/sgml/pg_xlogdump.sgml | 12 ++
4 files changed, 229 insertions(+), 14 deletions(-)
diff --git a/contrib/pg_xlogdump/pg_xlogdump.c b/contrib/pg_xlogdump/pg_xlogdump.c
index c555786..0a176bb 100644
--- a/contrib/pg_xlogdump/pg_xlogdump.c
+++ b/contrib/pg_xlogdump/pg_xlogdump.c
@@ -15,9 +15,10 @@
#include <dirent.h>
#include <unistd.h>
-#include "access/xlog.h"
#include "access/xlogreader.h"
#include "access/transam.h"
+#include "catalog/pg_control.h"
+#include "catalog/storage_xlog.h"
#include "common/fe_memutils.h"
#include "getopt_long.h"
#include "rmgrdesc.h"
@@ -41,6 +42,8 @@ typedef struct XLogDumpConfig
int stop_after_records;
int already_displayed_records;
bool follow;
+ bool stats;
+ bool stats_per_record;
/* filter options */
int filter_by_rmgr;
@@ -48,6 +51,22 @@ typedef struct XLogDumpConfig
bool filter_by_xid_enabled;
} XLogDumpConfig;
+typedef struct Stats
+{
+ uint64 count;
+ uint64 rec_len;
+ uint64 fpi_len;
+} Stats;
+
+#define MAX_XLINFO_TYPES 16
+
+typedef struct XLogDumpStats
+{
+ uint64 count;
+ Stats rmgr_stats[RM_NEXT_ID];
+ Stats record_stats[RM_NEXT_ID][MAX_XLINFO_TYPES];
+} XLogDumpStats;
+
static void
fatal_error(const char *fmt,...)
__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
@@ -322,22 +341,48 @@ XLogDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen,
}
/*
- * Print a record to stdout
+ * Store per-rmgr and per-record statistics for a given record.
*/
static void
-XLogDumpDisplayRecord(XLogDumpConfig *config, XLogRecPtr ReadRecPtr, XLogRecord *record)
+XLogDumpCountRecord(XLogDumpConfig *config, XLogDumpStats *stats, XLogRecPtr ReadRecPtr, XLogRecord *record)
{
- const RmgrDescData *desc = &RmgrDescTable[record->xl_rmid];
+ RmgrId rmid;
+ uint8 recid;
- if (config->filter_by_rmgr != -1 &&
- config->filter_by_rmgr != record->xl_rmid)
- return;
+ stats->count++;
- if (config->filter_by_xid_enabled &&
- config->filter_by_xid != record->xl_xid)
- return;
+ /* Update per-rmgr statistics */
- config->already_displayed_records++;
+ rmid = record->xl_rmid;
+
+ stats->rmgr_stats[rmid].count++;
+ stats->rmgr_stats[rmid].rec_len +=
+ record->xl_len + SizeOfXLogRecord;
+ stats->rmgr_stats[rmid].fpi_len +=
+ record->xl_tot_len - (record->xl_len + SizeOfXLogRecord);
+
+ /*
+ * Update per-record statistics, where the record is identified by a
+ * combination of the RmgrId and the upper four bits of the xl_info
+ * field (to give sixteen possible entries per RmgrId).
+ */
+
+ recid = (record->xl_info & ~XLR_INFO_MASK) >> 4;
+
+ stats->record_stats[rmid][recid].count++;
+ stats->record_stats[rmid][recid].rec_len +=
+ record->xl_len + SizeOfXLogRecord;
+ stats->record_stats[rmid][recid].fpi_len +=
+ record->xl_tot_len - (record->xl_len + SizeOfXLogRecord);
+}
+
+/*
+ * Print a record to stdout
+ */
+static void
+XLogDumpDisplayRecord(XLogDumpConfig *config, XLogRecPtr ReadRecPtr, XLogRecord *record)
+{
+ const RmgrDescData *desc = &RmgrDescTable[record->xl_rmid];
printf("rmgr: %-11s len (rec/tot): %6u/%6u, tx: %10u, lsn: %X/%08X, prev %X/%08X, bkp: %u%u%u%u, desc: ",
desc->rm_name,
@@ -380,6 +425,125 @@ XLogDumpDisplayRecord(XLogDumpConfig *config, XLogRecPtr ReadRecPtr, XLogRecord
}
}
+/*
+ * Display a single row of record counts and sizes for an rmgr or record.
+ */
+static void
+XLogDumpStatsRow(const char *name,
+ uint64 n, double n_pct,
+ uint64 rec_len, double rec_len_pct,
+ uint64 fpi_len, double fpi_len_pct,
+ uint64 total_len, double total_len_pct)
+{
+ printf("%-27s %20zu (%6.02f) %20zu (%6.02f) %20zu (%6.02f) %20zu (%6.02f)\n",
+ name, n, n_pct, rec_len, rec_len_pct, fpi_len, fpi_len_pct,
+ total_len, total_len_pct);
+}
+
+
+/*
+ * Display summary statistics about the records seen so far.
+ */
+static void
+XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats)
+{
+ int ri, rj;
+ uint64 total_count = 0;
+ uint64 total_rec_len = 0;
+ uint64 total_fpi_len = 0;
+ uint64 total_len = 0;
+
+ /*
+ * Make a first pass to calculate column totals:
+ * count(*),
+ * sum(xl_len+SizeOfXLogRecord),
+ * sum(xl_tot_len-xl_len-SizeOfXLogRecord), and
+ * sum(xl_tot_len).
+ * These are used to calculate percentages for each record type.
+ */
+
+ for (ri = 0; ri < RM_NEXT_ID; ri++)
+ {
+ total_count += stats->rmgr_stats[ri].count;
+ total_rec_len += stats->rmgr_stats[ri].rec_len;
+ total_fpi_len += stats->rmgr_stats[ri].fpi_len;
+ }
+ total_len = total_rec_len+total_fpi_len;
+
+ /*
+ * 27 is strlen("Transaction/COMMIT_PREPARED"),
+ * 20 is strlen(2^64), 8 is strlen("(100.00%)")
+ */
+
+ printf("%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n"
+ "%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n",
+ "Type", "N", "(%)", "Record size", "(%)", "FPI size", "(%)", "Combined size", "(%)",
+ "----", "-", "---", "-----------", "---", "--------", "---", "-------------", "---");
+
+ for (ri = 0; ri < RM_NEXT_ID; ri++)
+ {
+ uint64 count, rec_len, fpi_len, tot_len;
+ const RmgrDescData *desc = &RmgrDescTable[ri];
+
+ if (!config->stats_per_record)
+ {
+ count = stats->rmgr_stats[ri].count;
+ rec_len = stats->rmgr_stats[ri].rec_len;
+ fpi_len = stats->rmgr_stats[ri].fpi_len;
+ tot_len = rec_len + fpi_len;
+
+ XLogDumpStatsRow(desc->rm_name,
+ count, 100 * (double)count / total_count,
+ rec_len, 100 * (double)rec_len / total_rec_len,
+ fpi_len, 100 * (double)fpi_len / total_fpi_len,
+ tot_len, 100 * (double)tot_len / total_len);
+ }
+ else
+ {
+ for (rj = 0; rj < MAX_XLINFO_TYPES; rj++)
+ {
+ const char *id;
+
+ count = stats->record_stats[ri][rj].count;
+ rec_len = stats->record_stats[ri][rj].rec_len;
+ fpi_len = stats->record_stats[ri][rj].fpi_len;
+ tot_len = rec_len + fpi_len;
+
+ /* Skip undefined combinations and ones that didn't occur */
+ if (count == 0)
+ continue;
+
+ id = desc->rm_identify(rj << 4);
+ if (id == NULL)
+ id = psprintf("0x%x", rj << 4);
+
+ XLogDumpStatsRow(psprintf("%s/%s", desc->rm_name, id),
+ count, 100 * (double)count / total_count,
+ rec_len, 100 * (double)rec_len / total_rec_len,
+ fpi_len, 100 * (double)fpi_len / total_fpi_len,
+ tot_len, 100 * (double)tot_len / total_len);
+ }
+ }
+ }
+
+ printf("%-27s %20s %8s %20s %8s %20s %8s %20s\n",
+ "", "--------", "", "--------", "", "--------", "", "--------");
+
+ /*
+ * The percentages in earlier rows were calculated against the
+ * column total, but the ones that follow are against the row total.
+ * Note that these are displayed with a % symbol to differentiate
+ * them from the earlier ones, and are thus up to 9 characters long.
+ */
+
+ printf("%-27s %20zu %-9s%20zu %-9s%20zu %-9s%20zu %-6s\n",
+ "Total",
+ stats->count, "",
+ total_rec_len, psprintf("[%.02f%%]", 100 * (double)total_rec_len / total_len),
+ total_fpi_len, psprintf("[%.02f%%]", 100 * (double)total_fpi_len / total_len),
+ total_len, "[100%]");
+}
+
static void
usage(void)
{
@@ -401,6 +565,8 @@ usage(void)
printf(" (default: 1 or the value used in STARTSEG)\n");
printf(" -V, --version output version information, then exit\n");
printf(" -x, --xid=XID only show records with TransactionId XID\n");
+ printf(" -z, --stats[=record] show statistics instead of records\n");
+ printf(" (optionally, show per-record statistics)\n");
printf(" -?, --help show this help, then exit\n");
}
@@ -412,6 +578,7 @@ main(int argc, char **argv)
XLogReaderState *xlogreader_state;
XLogDumpPrivate private;
XLogDumpConfig config;
+ XLogDumpStats stats;
XLogRecord *record;
XLogRecPtr first_record;
char *errormsg;
@@ -428,6 +595,7 @@ main(int argc, char **argv)
{"timeline", required_argument, NULL, 't'},
{"xid", required_argument, NULL, 'x'},
{"version", no_argument, NULL, 'V'},
+ {"stats", optional_argument, NULL, 'z'},
{NULL, 0, NULL, 0}
};
@@ -438,6 +606,7 @@ main(int argc, char **argv)
memset(&private, 0, sizeof(XLogDumpPrivate));
memset(&config, 0, sizeof(XLogDumpConfig));
+ memset(&stats, 0, sizeof(XLogDumpStats));
private.timeline = 1;
private.startptr = InvalidXLogRecPtr;
@@ -451,6 +620,8 @@ main(int argc, char **argv)
config.filter_by_rmgr = -1;
config.filter_by_xid = InvalidTransactionId;
config.filter_by_xid_enabled = false;
+ config.stats = false;
+ config.stats_per_record = false;
if (argc <= 1)
{
@@ -458,7 +629,7 @@ main(int argc, char **argv)
goto bad_argument;
}
- while ((option = getopt_long(argc, argv, "be:?fn:p:r:s:t:Vx:",
+ while ((option = getopt_long(argc, argv, "be:?fn:p:r:s:t:Vx:z::",
long_options, &optindex)) != -1)
{
switch (option)
@@ -551,6 +722,21 @@ main(int argc, char **argv)
}
config.filter_by_xid_enabled = true;
break;
+ case 'z':
+ config.stats = true;
+ config.stats_per_record = false;
+ if (optarg)
+ {
+ if (strcmp(optarg, "record") == 0)
+ config.stats_per_record = true;
+ else if (strcmp(optarg, "rmgr") != 0)
+ {
+ fprintf(stderr, "%s: unrecognised argument to --stats: %s\n",
+ progname, optarg);
+ goto bad_argument;
+ }
+ }
+ break;
default:
goto bad_argument;
}
@@ -711,14 +897,30 @@ main(int argc, char **argv)
/* after reading the first record, continue at next one */
first_record = InvalidXLogRecPtr;
- XLogDumpDisplayRecord(&config, xlogreader_state->ReadRecPtr, record);
+
+ if (config.filter_by_rmgr != -1 &&
+ config.filter_by_rmgr != record->xl_rmid)
+ continue;
+
+ if (config.filter_by_xid_enabled &&
+ config.filter_by_xid != record->xl_xid)
+ continue;
+
+ if (config.stats == true)
+ XLogDumpCountRecord(&config, &stats, xlogreader_state->ReadRecPtr, record);
+ else
+ XLogDumpDisplayRecord(&config, xlogreader_state->ReadRecPtr, record);
/* check whether we printed enough */
+ config.already_displayed_records++;
if (config.stop_after_records > 0 &&
config.already_displayed_records >= config.stop_after_records)
break;
}
+ if (config.stats == true)
+ XLogDumpDisplayStats(&config, &stats);
+
if (errormsg)
fatal_error("error in WAL record at %X/%X: %s\n",
(uint32) (xlogreader_state->ReadRecPtr >> 32),
diff --git a/contrib/pg_xlogdump/rmgrdesc.c b/contrib/pg_xlogdump/rmgrdesc.c
index 1064d34..dc27fd1 100644
--- a/contrib/pg_xlogdump/rmgrdesc.c
+++ b/contrib/pg_xlogdump/rmgrdesc.c
@@ -28,7 +28,7 @@
#include "utils/relmapper.h"
#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \
- { name, desc, },
+ { name, desc, identify, },
const RmgrDescData RmgrDescTable[RM_MAX_ID + 1] = {
#include "access/rmgrlist.h"
diff --git a/contrib/pg_xlogdump/rmgrdesc.h b/contrib/pg_xlogdump/rmgrdesc.h
index d964118..da805c5 100644
--- a/contrib/pg_xlogdump/rmgrdesc.h
+++ b/contrib/pg_xlogdump/rmgrdesc.h
@@ -14,6 +14,7 @@ typedef struct RmgrDescData
{
const char *rm_name;
void (*rm_desc) (StringInfo buf, XLogRecord *record);
+ const char *(*rm_identify) (uint8 info);
} RmgrDescData;
extern const RmgrDescData RmgrDescTable[];
diff --git a/doc/src/sgml/pg_xlogdump.sgml b/doc/src/sgml/pg_xlogdump.sgml
index 1d1a2ce..d9f4a6a 100644
--- a/doc/src/sgml/pg_xlogdump.sgml
+++ b/doc/src/sgml/pg_xlogdump.sgml
@@ -180,6 +180,18 @@ PostgreSQL documentation
</varlistentry>
<varlistentry>
+ <term><option>-z</option></term>
+ <term><option>--stats[=record]</option></term>
+ <listitem>
+ <para>
+ Display summary statistics (number and size of records and
+ full-page images) instead of individual records. Optionally
+ generate statistics per-record instead of per-rmgr.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-?</></term>
<term><option>--help</></term>
<listitem>
--
1.9.1
At 2014-09-19 15:39:37 +0530, ams@2ndQuadrant.com wrote:
I hope I didn't miss anything this time.
But of course I did. The attached fixup makes the output of pg_xlogdump
match that of xlog_outdesc for unidentifiable records (UNKNOWN (%x)).
Sorry for the inconvenience.
-- Abhijit
Attachments:
rmid-unknown-fixup.difftext/x-diff; charset=us-asciiDownload
diff --git a/contrib/pg_xlogdump/pg_xlogdump.c b/contrib/pg_xlogdump/pg_xlogdump.c
index 0a176bb..7686a4f 100644
--- a/contrib/pg_xlogdump/pg_xlogdump.c
+++ b/contrib/pg_xlogdump/pg_xlogdump.c
@@ -515,7 +515,7 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats)
id = desc->rm_identify(rj << 4);
if (id == NULL)
- id = psprintf("0x%x", rj << 4);
+ id = psprintf("UNKNOWN (%x)", rj << 4);
XLogDumpStatsRow(psprintf("%s/%s", desc->rm_name, id),
count, 100 * (double)count / total_count,
Hi,
On 2014-09-19 15:39:37 +0530, Abhijit Menon-Sen wrote:
I've attached the revised patch, split up differently:
1. Introduce rm_identify, change rm_desc, glue the two together in
xlog.c
2. Introduce pg_xlogdump --stats[=record].
I've pushed these after some fixing up.
As we previously discussed, I think we might want to adjust the stats
further. But this is already really useful.
Thanks!
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Andres Freund wrote:
Hi,
On 2014-09-19 15:39:37 +0530, Abhijit Menon-Sen wrote:
I've attached the revised patch, split up differently:
1. Introduce rm_identify, change rm_desc, glue the two together in
xlog.c
2. Introduce pg_xlogdump --stats[=record].I've pushed these after some fixing up.
Hm, did you keep the static thingy you mentioned upthread (append_init
which is duped unless I read wrong)? There's quite some angst due to
pg_dump's fmtId() -- I don't think we should be introducing more such
things ...
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2014-09-19 19:34:08 -0300, Alvaro Herrera wrote:
Andres Freund wrote:
Hi,
On 2014-09-19 15:39:37 +0530, Abhijit Menon-Sen wrote:
I've attached the revised patch, split up differently:
1. Introduce rm_identify, change rm_desc, glue the two together in
xlog.c
2. Introduce pg_xlogdump --stats[=record].I've pushed these after some fixing up.
Hm, did you keep the static thingy you mentioned upthread (append_init
which is duped unless I read wrong)?
Yes, I did.
There's quite some angst due to pg_dump's fmtId() -- I don't think we
should be introducing more such things ...
I don't think these two are comparable. I don't really see many more
users of this springing up and printing the identity of two different
records in the same printf doesn't seem likely either.
Greetings,
Andres Freund
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers