diff --git a/src/backend/access/rmgrdesc/xlogdesc.c b/src/backend/access/rmgrdesc/xlogdesc.c index 3200f777f5..9aee7279a4 100644 --- a/src/backend/access/rmgrdesc/xlogdesc.c +++ b/src/backend/access/rmgrdesc/xlogdesc.c @@ -74,6 +74,13 @@ xlog_desc(StringInfo buf, XLogReaderState *record) memcpy(&nextOid, rec, sizeof(Oid)); appendStringInfo(buf, "%u", nextOid); } + else if (info == XLOG_SWITCH) + { + uint32 junk_len; + junk_len = xlog_switch_junk_len(record); + + appendStringInfo(buf, "trailing-bytes: %u", junk_len); + } else if (info == XLOG_RESTORE_POINT) { xl_restore_point *xlrec = (xl_restore_point *) rec; @@ -142,6 +149,30 @@ xlog_desc(StringInfo buf, XLogReaderState *record) } } +uint32 +xlog_switch_junk_len(XLogReaderState *record) +{ + uint32 junk_len; + XLogSegNo startSegNo; + XLogSegNo endSegNo; + + XLByteToSeg(record->ReadRecPtr, startSegNo, record->segcxt.ws_segsize); + XLByteToSeg(record->EndRecPtr - 1, endSegNo, record->segcxt.ws_segsize); + + junk_len = record->EndRecPtr - record->ReadRecPtr - XLogRecGetTotalLen(record); + /* + * If the wal switch record spread on two segments, we should extra minus the + * long page head. I mean the case when the remain size of a wal segment can not + * afford a XLogRecord struct for XLOG_SWITCH. + */ + if(startSegNo != endSegNo) + junk_len -= SizeOfXLogLongPHD; + + Assert(junk_len >= 0); + + return junk_len; +} + const char * xlog_identify(uint8 info) { diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c index 31e99c2a6d..0df4ddcf72 100644 --- a/src/bin/pg_waldump/pg_waldump.c +++ b/src/bin/pg_waldump/pg_waldump.c @@ -24,6 +24,7 @@ #include "common/logging.h" #include "getopt_long.h" #include "rmgrdesc.h" +#include "catalog/pg_control.h" static const char *progname; @@ -66,6 +67,8 @@ typedef struct Stats typedef struct XLogDumpStats { uint64 count; + uint64 count_xlog_switch; + uint32 junk_size; Stats rmgr_stats[RM_NEXT_ID]; Stats record_stats[RM_NEXT_ID][MAX_XLINFO_TYPES]; } XLogDumpStats; @@ -416,12 +419,21 @@ XLogDumpCountRecord(XLogDumpConfig *config, XLogDumpStats *stats, uint8 recid; uint32 rec_len; uint32 fpi_len; + uint32 junk_len; + uint8 info; stats->count++; rmid = XLogRecGetRmid(record); + info = XLogRecGetInfo(record) & ~XLR_INFO_MASK; XLogDumpRecordLen(record, &rec_len, &fpi_len); + if(RM_XLOG_ID == rmid && XLOG_SWITCH == info) + { + junk_len = xlog_switch_junk_len(record); + stats->count_xlog_switch++; + stats->junk_size += junk_len; + } /* Update per-rmgr statistics */ @@ -438,6 +450,14 @@ XLogDumpCountRecord(XLogDumpConfig *config, XLogDumpStats *stats, recid = XLogRecGetInfo(record) >> 4; + /* + * XXX: There is a special case for XACT records. Those records use the MSB + * of recid for another purpose. Ignore that bit in that case. + */ + if (rmid == RM_XACT_ID) + recid &= 0x07; + + stats->record_stats[rmid][recid].count++; stats->record_stats[rmid][recid].rec_len += rec_len; stats->record_stats[rmid][recid].fpi_len += fpi_len; @@ -610,6 +630,7 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats) uint64 total_len = 0; double rec_len_pct, fpi_len_pct; + const char *switch_junk_id; /* * Each row shows its percentages of the total, so make a first pass to @@ -622,7 +643,9 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats) total_rec_len += stats->rmgr_stats[ri].rec_len; total_fpi_len += stats->rmgr_stats[ri].fpi_len; } + total_rec_len += stats->junk_size; total_len = total_rec_len + total_fpi_len; + total_count += stats->count_xlog_switch; /* * 27 is strlen("Transaction/COMMIT_PREPARED"), 20 is strlen(2^64), 8 is @@ -652,12 +675,20 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats) XLogDumpStatsRow(desc->rm_name, count, total_count, rec_len, total_rec_len, fpi_len, total_fpi_len, tot_len, total_len); + if(RM_XLOG_ID == ri) + { + switch_junk_id = "XLOGSwitchJunk"; + XLogDumpStatsRow(psprintf("%s", switch_junk_id), + stats->count_xlog_switch, total_count, stats->junk_size, total_rec_len, + 0, total_fpi_len, stats->junk_size, total_len); + } } else { for (rj = 0; rj < MAX_XLINFO_TYPES; rj++) { const char *id; + uint8 info; count = stats->record_stats[ri][rj].count; rec_len = stats->record_stats[ri][rj].rec_len; @@ -676,6 +707,12 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats) XLogDumpStatsRow(psprintf("%s/%s", desc->rm_name, id), count, total_count, rec_len, total_rec_len, fpi_len, total_fpi_len, tot_len, total_len); + info = (rj << 4) & ~XLR_INFO_MASK; + switch_junk_id = "XLOG/SWITCH_JUNK"; + if( XLOG_SWITCH == info && stats->count_xlog_switch > 0) + XLogDumpStatsRow(psprintf("%s", switch_junk_id), + stats->count_xlog_switch, total_count, stats->junk_size, total_rec_len, + 0, total_fpi_len, stats->junk_size, total_len); } } } diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h index 4146753d47..8cbc309108 100644 --- a/src/include/access/xlog_internal.h +++ b/src/include/access/xlog_internal.h @@ -315,6 +315,7 @@ extern XLogRecPtr RequestXLogSwitch(bool mark_unimportant); extern void GetOldestRestartPoint(XLogRecPtr *oldrecptr, TimeLineID *oldtli); +extern uint32 xlog_switch_junk_len(XLogReaderState *record); /* * Exported for the functions in timeline.c and xlogarchive.c. Only valid * in the startup process.