get rid of RM_HEAP2_ID
Making the XLogRecord header nicer has been proposed several times
[1]: /messages/by-id/20220715173731.6t3km5cww3f5ztfq@awork3.anarazel.de
could get rid of the separate xl_xact_info. There could be other
possibilities as well, but I haven't done anything in that direction.
The attached just gets as far as the modest goal mentioned in the
subject.
0001: Split xl_info into xl_info for rmgr-specific info and xl_geninfo
for generic flags. I used the XLogInsertExtended() idea from one of
Matthias's patches in [3]/messages/by-id/CAEze2Wjd3jY_UhhOGdGGnC6NO=+NmtNOmd=JaYv-v-nwBAiXXA@mail.gmail.com, but wrote the rest a different way to keep
churn small.
0002 and 0003: To simplify the rmgrs that have an opmask and separate
flag (I saw two obvious ones but I didn't make sure they were the only
ones), reserve the high 4 bits of xl_info for the "record type" (I see
xlogstats.c calls it a "recid", so that might be a better name) and
the lower 4 bits for the flag. Using the same scheme everywhere
simplifies things.
I've put the mask into these macros to reduce the places that know about them:
#define XLogRecGetRecType(decoder) ((decoder)->record->header.xl_info
& XLR_REC_TYPE_MASK)
#define XLogRecGetRecFlags(decoder) ((decoder)->record->header.xl_info
& XLR_REC_FLAGS_MASK)
The former is for callers that explicitly want to know about the
record type only, without flags. The latter is unused, since checking
a mask doesn't need to isolate all the masks first, so it may not end
up in the final version.
There are new XLR_* masks whose names reflect their new purpose
better, but they are the same values as the old ones. XLR_INFO_MASK is
kept around for compatibility, but it doesn't do anything useful since
the rmgr has the full byte available. In order for ~XLR_INFO_MASK to
become a no-op on a full byte, XLR_INFO_MASK has to be zero, which
looks very odd. Removing it would be clearer, at the cost of more
churn.
There is a small wrinkle in that heap_identify does different things
depending on presence of the XLOG_HEAP_INIT_PAGE flag, but
xact_identify() doesn't do that with XLOG_XACT_HAS_INFO, so the latter
still masks out the flags.
0004: get rid of RM_HEAP2_ID. This was simple once the prerequisites
were in place. All of the HEAP2_* macros keep the same name and only
differ in value. Heap rmgr is completely full so it might be good to
increase to 5 bits for the record type to give it some breathing room.
I wasn't sure about this comment in heapam_xlog.c -- it seems strange
that this property would occur exactly at the point where the first
heap rmgr id ran out of bits, but check world passes without doing
anything additional:
/*
* These operations don't overwrite MVCC data so no conflict processing is
* required. The ones in heap2 rmgr do.
*/
[1]: /messages/by-id/20220715173731.6t3km5cww3f5ztfq@awork3.anarazel.de
[2]: /messages/by-id/CA+Tgmoa7pNxxe_K=3mTHHZGSmnrc_YgApArx3OFHN2g57nzLNw@mail.gmail.com
[3]: /messages/by-id/CAEze2Wjd3jY_UhhOGdGGnC6NO=+NmtNOmd=JaYv-v-nwBAiXXA@mail.gmail.com
--
John Naylor
Amazon Web Services
Attachments:
v1-0002-Get-rid-of-XLOG_XACT_OPMASK.patchapplication/x-patch; name=v1-0002-Get-rid-of-XLOG_XACT_OPMASK.patchDownload
From 08edc80158627bd23018d437e31ee47e2fbd0553 Mon Sep 17 00:00:00 2001
From: John Naylor <john.naylor@postgresql.org>
Date: Sun, 5 Oct 2025 13:40:15 +0700
Subject: [PATCH v1 2/4] Get rid of XLOG_XACT_OPMASK
Since we can now use the lower 4 bits of xl_info for rmgr-specific
flags, move XLOG_XACT_HAS_INFO into that space, making the op mask
unnecessary.
---
src/backend/access/rmgrdesc/xactdesc.c | 4 ++--
src/backend/access/transam/twophase.c | 2 +-
src/backend/access/transam/xact.c | 2 +-
src/backend/access/transam/xlogrecovery.c | 17 ++++++++---------
src/backend/access/transam/xlogstats.c | 9 ---------
src/backend/postmaster/walsummarizer.c | 3 +--
src/backend/replication/logical/decode.c | 2 +-
src/bin/pg_rewind/parsexlog.c | 11 +++++------
src/include/access/xact.h | 11 ++++-------
src/include/access/xlogreader.h | 2 ++
src/include/access/xlogrecord.h | 9 +++++++--
11 files changed, 32 insertions(+), 40 deletions(-)
diff --git a/src/backend/access/rmgrdesc/xactdesc.c b/src/backend/access/rmgrdesc/xactdesc.c
index f0f696855b9..4fe4b0c1eab 100644
--- a/src/backend/access/rmgrdesc/xactdesc.c
+++ b/src/backend/access/rmgrdesc/xactdesc.c
@@ -439,7 +439,7 @@ void
xact_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
- uint8 info = XLogRecGetInfo(record) & XLOG_XACT_OPMASK;
+ uint8 info = XLogRecGetRecType(record);
if (info == XLOG_XACT_COMMIT || info == XLOG_XACT_COMMIT_PREPARED)
{
@@ -488,7 +488,7 @@ xact_identify(uint8 info)
{
const char *id = NULL;
- switch (info & XLOG_XACT_OPMASK)
+ switch (info & XLR_REC_TYPE_MASK)
{
case XLOG_XACT_COMMIT:
id = "COMMIT";
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index d8e2fce2c99..9802f5fe944 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -1444,7 +1444,7 @@ XlogReadTwoPhaseData(XLogRecPtr lsn, char **buf, int *len)
}
if (XLogRecGetRmid(xlogreader) != RM_XACT_ID ||
- (XLogRecGetInfo(xlogreader) & XLOG_XACT_OPMASK) != XLOG_XACT_PREPARE)
+ XLogRecGetRecType(xlogreader) != XLOG_XACT_PREPARE)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("expected two-phase state data is not present in WAL at %X/%08X",
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index fc06474fc75..29b9ddd3096 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -6376,7 +6376,7 @@ xact_redo_abort(xl_xact_parsed_abort *parsed, TransactionId xid,
void
xact_redo(XLogReaderState *record)
{
- uint8 info = XLogRecGetInfo(record) & XLOG_XACT_OPMASK;
+ uint8 info = XLogRecGetRecType(record);
/* Backup blocks are not used in xact records */
Assert(!XLogRecHasAnyBlockRefs(record));
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index 3e3aae0e47c..d445851ac6f 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -2438,8 +2438,7 @@ checkTimeLineSwitch(XLogRecPtr lsn, TimeLineID newTLI, TimeLineID prevTLI,
static bool
getRecordTimestamp(XLogReaderState *record, TimestampTz *recordXtime)
{
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
- uint8 xact_info = info & XLOG_XACT_OPMASK;
+ uint8 info = XLogRecGetRecType(record);
uint8 rmid = XLogRecGetRmid(record);
if (rmid == RM_XLOG_ID && info == XLOG_RESTORE_POINT)
@@ -2447,14 +2446,14 @@ getRecordTimestamp(XLogReaderState *record, TimestampTz *recordXtime)
*recordXtime = ((xl_restore_point *) XLogRecGetData(record))->rp_time;
return true;
}
- if (rmid == RM_XACT_ID && (xact_info == XLOG_XACT_COMMIT ||
- xact_info == XLOG_XACT_COMMIT_PREPARED))
+ if (rmid == RM_XACT_ID && (info == XLOG_XACT_COMMIT ||
+ info == XLOG_XACT_COMMIT_PREPARED))
{
*recordXtime = ((xl_xact_commit *) XLogRecGetData(record))->xact_time;
return true;
}
- if (rmid == RM_XACT_ID && (xact_info == XLOG_XACT_ABORT ||
- xact_info == XLOG_XACT_ABORT_PREPARED))
+ if (rmid == RM_XACT_ID && (info == XLOG_XACT_ABORT ||
+ info == XLOG_XACT_ABORT_PREPARED))
{
*recordXtime = ((xl_xact_abort *) XLogRecGetData(record))->xact_time;
return true;
@@ -2632,7 +2631,7 @@ recoveryStopsBefore(XLogReaderState *record)
if (XLogRecGetRmid(record) != RM_XACT_ID)
return false;
- xact_info = XLogRecGetInfo(record) & XLOG_XACT_OPMASK;
+ xact_info = XLogRecGetRecType(record);
if (xact_info == XLOG_XACT_COMMIT)
{
@@ -2799,7 +2798,7 @@ recoveryStopsAfter(XLogReaderState *record)
if (rmid != RM_XACT_ID)
return false;
- xact_info = info & XLOG_XACT_OPMASK;
+ xact_info = info;
if (xact_info == XLOG_XACT_COMMIT ||
xact_info == XLOG_XACT_COMMIT_PREPARED ||
@@ -3022,7 +3021,7 @@ recoveryApplyDelay(XLogReaderState *record)
if (XLogRecGetRmid(record) != RM_XACT_ID)
return false;
- xact_info = XLogRecGetInfo(record) & XLOG_XACT_OPMASK;
+ xact_info = XLogRecGetRecType(record);
if (xact_info != XLOG_XACT_COMMIT &&
xact_info != XLOG_XACT_COMMIT_PREPARED)
diff --git a/src/backend/access/transam/xlogstats.c b/src/backend/access/transam/xlogstats.c
index 4ddd204bd29..aca9a378ce6 100644
--- a/src/backend/access/transam/xlogstats.c
+++ b/src/backend/access/transam/xlogstats.c
@@ -80,15 +80,6 @@ XLogRecStoreStats(XLogStats *stats, XLogReaderState *record)
recid = XLogRecGetInfo(record) >> 4;
- /*
- * XACT records need to be handled differently. Those records use the
- * first bit of those four bits for an optional flag variable and the
- * following three bits for the opcode. We filter opcode out of xl_info
- * and use it as the identifier of the record.
- */
- 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;
diff --git a/src/backend/postmaster/walsummarizer.c b/src/backend/postmaster/walsummarizer.c
index e1f142f20c7..f18456f48fb 100644
--- a/src/backend/postmaster/walsummarizer.c
+++ b/src/backend/postmaster/walsummarizer.c
@@ -1366,8 +1366,7 @@ SummarizeSmgrRecord(XLogReaderState *xlogreader, BlockRefTable *brtab)
static void
SummarizeXactRecord(XLogReaderState *xlogreader, BlockRefTable *brtab)
{
- uint8 info = XLogRecGetInfo(xlogreader) & ~XLR_INFO_MASK;
- uint8 xact_info = info & XLOG_XACT_OPMASK;
+ uint8 xact_info = XLogRecGetRecType(xlogreader);
if (xact_info == XLOG_XACT_COMMIT ||
xact_info == XLOG_XACT_COMMIT_PREPARED)
diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c
index cc03f0706e9..af7465e1bbf 100644
--- a/src/backend/replication/logical/decode.c
+++ b/src/backend/replication/logical/decode.c
@@ -203,7 +203,7 @@ xact_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
SnapBuild *builder = ctx->snapshot_builder;
ReorderBuffer *reorder = ctx->reorder;
XLogReaderState *r = buf->record;
- uint8 info = XLogRecGetInfo(r) & XLOG_XACT_OPMASK;
+ uint8 info = XLogRecGetRecType(r);
/*
* If the snapshot isn't yet fully built, we cannot decode anything, so
diff --git a/src/bin/pg_rewind/parsexlog.c b/src/bin/pg_rewind/parsexlog.c
index dbc1c50b100..4890f2413df 100644
--- a/src/bin/pg_rewind/parsexlog.c
+++ b/src/bin/pg_rewind/parsexlog.c
@@ -390,8 +390,7 @@ extractPageInfo(XLogReaderState *record)
{
int block_id;
RmgrId rmid = XLogRecGetRmid(record);
- uint8 info = XLogRecGetInfo(record);
- uint8 rminfo = info & ~XLR_INFO_MASK;
+ uint8 rminfo = XLogRecGetRecType(record);
uint8 geninfo = XLogRecGetGeninfo(record);
/* Is this a special record type that I recognize? */
@@ -441,10 +440,10 @@ extractPageInfo(XLogReaderState *record)
*/
}
else if (rmid == RM_XACT_ID &&
- ((rminfo & XLOG_XACT_OPMASK) == XLOG_XACT_COMMIT ||
- (rminfo & XLOG_XACT_OPMASK) == XLOG_XACT_COMMIT_PREPARED ||
- (rminfo & XLOG_XACT_OPMASK) == XLOG_XACT_ABORT ||
- (rminfo & XLOG_XACT_OPMASK) == XLOG_XACT_ABORT_PREPARED))
+ (rminfo == XLOG_XACT_COMMIT ||
+ rminfo == XLOG_XACT_COMMIT_PREPARED ||
+ rminfo == XLOG_XACT_ABORT ||
+ rminfo == XLOG_XACT_ABORT_PREPARED))
{
/*
* These records can include "dropped rels". We can safely ignore
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 4528e51829e..6eabc7bb40a 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -164,8 +164,9 @@ typedef struct SavedTransactionCharacteristics
*/
/*
- * XLOG allows to store some information in high 4 bits of log record xl_info
- * field. We use 3 for the opcode, and one about an optional flag variable.
+ * XLOG allows to store record type in high 4 bits of log record xl_info
+ * field and the lower 4 bits for optional flags. We use the high bits
+ * for the opcode and the lower for the xinfo bit.
*/
#define XLOG_XACT_COMMIT 0x00
#define XLOG_XACT_PREPARE 0x10
@@ -174,13 +175,9 @@ typedef struct SavedTransactionCharacteristics
#define XLOG_XACT_ABORT_PREPARED 0x40
#define XLOG_XACT_ASSIGNMENT 0x50
#define XLOG_XACT_INVALIDATIONS 0x60
-/* free opcode 0x70 */
-
-/* mask for filtering opcodes out of xl_info */
-#define XLOG_XACT_OPMASK 0x70
/* does this record have a 'xinfo' field or not */
-#define XLOG_XACT_HAS_INFO 0x80
+#define XLOG_XACT_HAS_INFO 0x01
/*
* The following flags, stored in xinfo, determine which information is
diff --git a/src/include/access/xlogreader.h b/src/include/access/xlogreader.h
index 6faf02e840f..21f156b6c04 100644
--- a/src/include/access/xlogreader.h
+++ b/src/include/access/xlogreader.h
@@ -408,6 +408,8 @@ extern bool DecodeXLogRecord(XLogReaderState *state,
#define XLogRecGetTotalLen(decoder) ((decoder)->record->header.xl_tot_len)
#define XLogRecGetPrev(decoder) ((decoder)->record->header.xl_prev)
#define XLogRecGetInfo(decoder) ((decoder)->record->header.xl_info)
+#define XLogRecGetRecType(decoder) ((decoder)->record->header.xl_info & XLR_REC_TYPE_MASK)
+#define XLogRecGetRecFlags(decoder) ((decoder)->record->header.xl_info & XLR_REC_FLAGS_MASK)
#define XLogRecGetGeninfo(decoder) ((decoder)->record->header.xl_geninfo)
#define XLogRecGetRmid(decoder) ((decoder)->record->header.xl_rmid)
#define XLogRecGetXid(decoder) ((decoder)->record->header.xl_xid)
diff --git a/src/include/access/xlogrecord.h b/src/include/access/xlogrecord.h
index 9a587bc5b01..a307945170b 100644
--- a/src/include/access/xlogrecord.h
+++ b/src/include/access/xlogrecord.h
@@ -66,8 +66,13 @@ typedef struct XLogRecord
* All of xl_info may be used freely by rmgr. The high 4 bits are the
* record type and the rest are optional flag bits.
*/
-#define XLR_INFO_MASK 0x0F
-#define XLR_RMGR_INFO_MASK 0xF0
+#define XLR_REC_TYPE_MASK 0xF0
+#define XLR_REC_FLAGS_MASK 0x0F
+
+// WIP: compatibility for sites that historically used
+// ~XLR_INFO_MASK to access rmgr info
+// It would be nice to get rid of this
+#define XLR_INFO_MASK 0x00
/*
* XLogReader needs to allocate all the data of a WAL record in a single
--
2.51.0
v1-0003-Get-rid-of-XLOG_HEAP_OPMASK.patchapplication/x-patch; name=v1-0003-Get-rid-of-XLOG_HEAP_OPMASK.patchDownload
From 7b24fd5139507a80d0edba994abe0a80ae1ac243 Mon Sep 17 00:00:00 2001
From: John Naylor <john.naylor@postgresql.org>
Date: Sun, 5 Oct 2025 14:17:44 +0700
Subject: [PATCH v1 3/4] Get rid of XLOG_HEAP_OPMASK
---
src/backend/access/heap/heapam_xlog.c | 8 ++++----
src/backend/access/rmgrdesc/heapdesc.c | 6 ++----
src/backend/replication/logical/decode.c | 4 ++--
src/include/access/heapam_xlog.h | 11 +++++------
4 files changed, 13 insertions(+), 16 deletions(-)
diff --git a/src/backend/access/heap/heapam_xlog.c b/src/backend/access/heap/heapam_xlog.c
index cf843277938..e6cd0955818 100644
--- a/src/backend/access/heap/heapam_xlog.c
+++ b/src/backend/access/heap/heapam_xlog.c
@@ -1179,14 +1179,14 @@ heap_xlog_inplace(XLogReaderState *record)
void
heap_redo(XLogReaderState *record)
{
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetRecType(record);
/*
* These operations don't overwrite MVCC data so no conflict processing is
* required. The ones in heap2 rmgr do.
*/
- switch (info & XLOG_HEAP_OPMASK)
+ switch (info)
{
case XLOG_HEAP_INSERT:
heap_xlog_insert(record);
@@ -1225,9 +1225,9 @@ heap_redo(XLogReaderState *record)
void
heap2_redo(XLogReaderState *record)
{
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetRecType(record);
- switch (info & XLOG_HEAP_OPMASK)
+ switch (info)
{
case XLOG_HEAP2_PRUNE_ON_ACCESS:
case XLOG_HEAP2_PRUNE_VACUUM_SCAN:
diff --git a/src/backend/access/rmgrdesc/heapdesc.c b/src/backend/access/rmgrdesc/heapdesc.c
index 82b62c95de5..dd5ae6b295b 100644
--- a/src/backend/access/rmgrdesc/heapdesc.c
+++ b/src/backend/access/rmgrdesc/heapdesc.c
@@ -184,9 +184,8 @@ void
heap_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetRecType(record);
- info &= XLOG_HEAP_OPMASK;
if (info == XLOG_HEAP_INSERT)
{
xl_heap_insert *xlrec = (xl_heap_insert *) rec;
@@ -264,9 +263,8 @@ void
heap2_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetRecType(record);
- info &= XLOG_HEAP_OPMASK;
if (info == XLOG_HEAP2_PRUNE_ON_ACCESS ||
info == XLOG_HEAP2_PRUNE_VACUUM_SCAN ||
info == XLOG_HEAP2_PRUNE_VACUUM_CLEANUP)
diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c
index af7465e1bbf..cf298a215ee 100644
--- a/src/backend/replication/logical/decode.c
+++ b/src/backend/replication/logical/decode.c
@@ -404,7 +404,7 @@ standby_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
void
heap2_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
{
- uint8 info = XLogRecGetInfo(buf->record) & XLOG_HEAP_OPMASK;
+ uint8 info = XLogRecGetRecType(buf->record);
TransactionId xid = XLogRecGetXid(buf->record);
SnapBuild *builder = ctx->snapshot_builder;
@@ -468,7 +468,7 @@ heap2_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
void
heap_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
{
- uint8 info = XLogRecGetInfo(buf->record) & XLOG_HEAP_OPMASK;
+ uint8 info = XLogRecGetRecType(buf->record);
TransactionId xid = XLogRecGetXid(buf->record);
SnapBuild *builder = ctx->snapshot_builder;
diff --git a/src/include/access/heapam_xlog.h b/src/include/access/heapam_xlog.h
index d4c0625b632..6ebfdb32369 100644
--- a/src/include/access/heapam_xlog.h
+++ b/src/include/access/heapam_xlog.h
@@ -27,8 +27,9 @@
/*
* WAL record definitions for heapam.c's WAL operations
*
- * XLOG allows to store some information in high 4 bits of log
- * record xl_info field. We use 3 for opcode and one for init bit.
+ * XLOG allows to store record type in high 4 bits of log record xl_info
+ * field and the lower 4 bits for optional flags. We use the high bits
+ * for the opcode and the lower for the init bit.
*/
#define XLOG_HEAP_INSERT 0x00
#define XLOG_HEAP_DELETE 0x10
@@ -39,17 +40,15 @@
#define XLOG_HEAP_LOCK 0x60
#define XLOG_HEAP_INPLACE 0x70
-#define XLOG_HEAP_OPMASK 0x70
/*
* When we insert 1st item on new page in INSERT, UPDATE, HOT_UPDATE,
* or MULTI_INSERT, we can (and we do) restore entire page in redo
*/
-#define XLOG_HEAP_INIT_PAGE 0x80
+#define XLOG_HEAP_INIT_PAGE 0x01
/*
* We ran out of opcodes, so heapam.c now has a second RmgrId. These opcodes
* are associated with RM_HEAP2_ID, but are not logically different from
- * the ones above associated with RM_HEAP_ID. XLOG_HEAP_OPMASK applies to
- * these, too.
+ * the ones above associated with RM_HEAP_ID.
*
* There's no difference between XLOG_HEAP2_PRUNE_ON_ACCESS,
* XLOG_HEAP2_PRUNE_VACUUM_SCAN and XLOG_HEAP2_PRUNE_VACUUM_CLEANUP records.
--
2.51.0
v1-0004-Get-rid-of-RM_HEAP2_ID.patchapplication/x-patch; name=v1-0004-Get-rid-of-RM_HEAP2_ID.patchDownload
From 448fabb2edefd714fad7f03cf0c445d53b74835e Mon Sep 17 00:00:00 2001
From: John Naylor <john.naylor@postgresql.org>
Date: Sun, 5 Oct 2025 15:21:03 +0700
Subject: [PATCH v1 4/4] Get rid of RM_HEAP2_ID
---
src/backend/access/heap/heapam.c | 8 +-
src/backend/access/heap/heapam_xlog.c | 15 +---
src/backend/access/heap/pruneheap.c | 2 +-
src/backend/access/heap/rewriteheap.c | 2 +-
src/backend/access/rmgrdesc/heapdesc.c | 22 +-----
src/backend/replication/logical/decode.c | 98 ++++++++----------------
src/bin/pg_waldump/t/001_basic.pl | 1 -
src/include/access/heapam_xlog.h | 35 ++++-----
src/include/access/rmgrlist.h | 1 -
9 files changed, 60 insertions(+), 124 deletions(-)
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index ed0c0c2dc9f..c8597417f15 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2634,7 +2634,7 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
/* filtering by origin on a row level is much more efficient */
XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
- recptr = XLogInsert(RM_HEAP2_ID, info);
+ recptr = XLogInsert(RM_HEAP_ID, info);
PageSetLSN(page, recptr);
}
@@ -5981,7 +5981,7 @@ l4:
XLogRegisterData(&xlrec, SizeOfHeapLockUpdated);
- recptr = XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_LOCK_UPDATED);
+ recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP2_LOCK_UPDATED);
PageSetLSN(page, recptr);
}
@@ -8825,7 +8825,7 @@ log_heap_visible(Relation rel, Buffer heap_buffer, Buffer vm_buffer,
flags |= REGBUF_NO_IMAGE;
XLogRegisterBuffer(1, heap_buffer, flags);
- recptr = XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_VISIBLE);
+ recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP2_VISIBLE);
return recptr;
}
@@ -9119,7 +9119,7 @@ log_heap_new_cid(Relation relation, HeapTuple tup)
/* will be looked at irrespective of origin */
- recptr = XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_NEW_CID);
+ recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP2_NEW_CID);
return recptr;
}
diff --git a/src/backend/access/heap/heapam_xlog.c b/src/backend/access/heap/heapam_xlog.c
index e6cd0955818..4817f55a5b9 100644
--- a/src/backend/access/heap/heapam_xlog.c
+++ b/src/backend/access/heap/heapam_xlog.c
@@ -1184,6 +1184,7 @@ heap_redo(XLogReaderState *record)
/*
* These operations don't overwrite MVCC data so no conflict processing is
* required. The ones in heap2 rmgr do.
+ * WIP: Is this a blocker for merging into one rmgr?
*/
switch (info)
@@ -1217,18 +1218,8 @@ heap_redo(XLogReaderState *record)
case XLOG_HEAP_INPLACE:
heap_xlog_inplace(record);
break;
- default:
- elog(PANIC, "heap_redo: unknown op code %u", info);
- }
-}
-void
-heap2_redo(XLogReaderState *record)
-{
- uint8 info = XLogRecGetRecType(record);
-
- switch (info)
- {
+ /* former heap2 */
case XLOG_HEAP2_PRUNE_ON_ACCESS:
case XLOG_HEAP2_PRUNE_VACUUM_SCAN:
case XLOG_HEAP2_PRUNE_VACUUM_CLEANUP:
@@ -1254,7 +1245,7 @@ heap2_redo(XLogReaderState *record)
heap_xlog_logical_rewrite(record);
break;
default:
- elog(PANIC, "heap2_redo: unknown op code %u", info);
+ elog(PANIC, "heap_redo: unknown op code %u", info);
}
}
diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c
index d8ea0c78f77..9411999ddab 100644
--- a/src/backend/access/heap/pruneheap.c
+++ b/src/backend/access/heap/pruneheap.c
@@ -2166,7 +2166,7 @@ log_heap_prune_and_freeze(Relation relation, Buffer buffer,
elog(ERROR, "unrecognized prune reason: %d", (int) reason);
break;
}
- recptr = XLogInsert(RM_HEAP2_ID, info);
+ recptr = XLogInsert(RM_HEAP_ID, info);
PageSetLSN(BufferGetPage(buffer), recptr);
}
diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c
index e6d2b5fced1..a78ba42931c 100644
--- a/src/backend/access/heap/rewriteheap.c
+++ b/src/backend/access/heap/rewriteheap.c
@@ -891,7 +891,7 @@ logical_heap_rewrite_flush_mappings(RewriteState state)
XLogRegisterData(waldata_start, len);
/* write xlog record */
- XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_REWRITE);
+ XLogInsert(RM_HEAP_ID, XLOG_HEAP2_REWRITE);
pfree(waldata_start);
}
diff --git a/src/backend/access/rmgrdesc/heapdesc.c b/src/backend/access/rmgrdesc/heapdesc.c
index dd5ae6b295b..a933e946ba6 100644
--- a/src/backend/access/rmgrdesc/heapdesc.c
+++ b/src/backend/access/rmgrdesc/heapdesc.c
@@ -257,15 +257,7 @@ heap_desc(StringInfo buf, XLogReaderState *record)
xlrec->dbId, xlrec->tsId,
xlrec->relcacheInitFileInval);
}
-}
-
-void
-heap2_desc(StringInfo buf, XLogReaderState *record)
-{
- char *rec = XLogRecGetData(record);
- uint8 info = XLogRecGetRecType(record);
-
- if (info == XLOG_HEAP2_PRUNE_ON_ACCESS ||
+ else if (info == XLOG_HEAP2_PRUNE_ON_ACCESS ||
info == XLOG_HEAP2_PRUNE_VACUUM_SCAN ||
info == XLOG_HEAP2_PRUNE_VACUUM_CLEANUP)
{
@@ -423,18 +415,8 @@ heap_identify(uint8 info)
case XLOG_HEAP_INPLACE:
id = "INPLACE";
break;
- }
- return id;
-}
-
-const char *
-heap2_identify(uint8 info)
-{
- const char *id = NULL;
-
- switch (info & ~XLR_INFO_MASK)
- {
+ /* former heap2 */
case XLOG_HEAP2_PRUNE_ON_ACCESS:
id = "PRUNE_ON_ACCESS";
break;
diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c
index cf298a215ee..eb1648e2192 100644
--- a/src/backend/replication/logical/decode.c
+++ b/src/backend/replication/logical/decode.c
@@ -398,70 +398,6 @@ standby_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
}
}
-/*
- * Handle rmgr HEAP2_ID records for LogicalDecodingProcessRecord().
- */
-void
-heap2_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
-{
- uint8 info = XLogRecGetRecType(buf->record);
- TransactionId xid = XLogRecGetXid(buf->record);
- SnapBuild *builder = ctx->snapshot_builder;
-
- ReorderBufferProcessXid(ctx->reorder, xid, buf->origptr);
-
- /*
- * If we don't have snapshot or we are just fast-forwarding, there is no
- * point in decoding data changes. However, it's crucial to build the base
- * snapshot during fast-forward mode (as is done in
- * SnapBuildProcessChange()) because we require the snapshot's xmin when
- * determining the candidate catalog_xmin for the replication slot. See
- * SnapBuildProcessRunningXacts().
- */
- if (SnapBuildCurrentState(builder) < SNAPBUILD_FULL_SNAPSHOT)
- return;
-
- switch (info)
- {
- case XLOG_HEAP2_MULTI_INSERT:
- if (SnapBuildProcessChange(builder, xid, buf->origptr) &&
- !ctx->fast_forward)
- DecodeMultiInsert(ctx, buf);
- break;
- case XLOG_HEAP2_NEW_CID:
- if (!ctx->fast_forward)
- {
- xl_heap_new_cid *xlrec;
-
- xlrec = (xl_heap_new_cid *) XLogRecGetData(buf->record);
- SnapBuildProcessNewCid(builder, xid, buf->origptr, xlrec);
-
- break;
- }
- case XLOG_HEAP2_REWRITE:
-
- /*
- * Although these records only exist to serve the needs of logical
- * decoding, all the work happens as part of crash or archive
- * recovery, so we don't need to do anything here.
- */
- break;
-
- /*
- * Everything else here is just low level physical stuff we're not
- * interested in.
- */
- case XLOG_HEAP2_PRUNE_ON_ACCESS:
- case XLOG_HEAP2_PRUNE_VACUUM_SCAN:
- case XLOG_HEAP2_PRUNE_VACUUM_CLEANUP:
- case XLOG_HEAP2_VISIBLE:
- case XLOG_HEAP2_LOCK_UPDATED:
- break;
- default:
- elog(ERROR, "unexpected RM_HEAP2_ID record type: %u", info);
- }
-}
-
/*
* Handle rmgr HEAP_ID records for LogicalDecodingProcessRecord().
*/
@@ -546,6 +482,40 @@ heap_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
/* we don't care about row level locks for now */
break;
+ case XLOG_HEAP2_MULTI_INSERT:
+ if (SnapBuildProcessChange(builder, xid, buf->origptr) &&
+ !ctx->fast_forward)
+ DecodeMultiInsert(ctx, buf);
+ break;
+ case XLOG_HEAP2_NEW_CID:
+ if (!ctx->fast_forward)
+ {
+ xl_heap_new_cid *xlrec;
+
+ xlrec = (xl_heap_new_cid *) XLogRecGetData(buf->record);
+ SnapBuildProcessNewCid(builder, xid, buf->origptr, xlrec);
+
+ break;
+ }
+ case XLOG_HEAP2_REWRITE:
+
+ /*
+ * Although these records only exist to serve the needs of logical
+ * decoding, all the work happens as part of crash or archive
+ * recovery, so we don't need to do anything here.
+ */
+ break;
+
+ /*
+ * Everything else here is just low level physical stuff we're not
+ * interested in.
+ */
+ case XLOG_HEAP2_PRUNE_ON_ACCESS:
+ case XLOG_HEAP2_PRUNE_VACUUM_SCAN:
+ case XLOG_HEAP2_PRUNE_VACUUM_CLEANUP:
+ case XLOG_HEAP2_VISIBLE:
+ case XLOG_HEAP2_LOCK_UPDATED:
+ break;
default:
elog(ERROR, "unexpected RM_HEAP_ID record type: %u", info);
break;
diff --git a/src/bin/pg_waldump/t/001_basic.pl b/src/bin/pg_waldump/t/001_basic.pl
index f26d75e01cf..01a7d3276e9 100644
--- a/src/bin/pg_waldump/t/001_basic.pl
+++ b/src/bin/pg_waldump/t/001_basic.pl
@@ -61,7 +61,6 @@ Tablespace
MultiXact
RelMap
Standby
-Heap2
Heap
Btree
Hash
diff --git a/src/include/access/heapam_xlog.h b/src/include/access/heapam_xlog.h
index 6ebfdb32369..3fcb9d5038d 100644
--- a/src/include/access/heapam_xlog.h
+++ b/src/include/access/heapam_xlog.h
@@ -39,30 +39,28 @@
#define XLOG_HEAP_CONFIRM 0x50
#define XLOG_HEAP_LOCK 0x60
#define XLOG_HEAP_INPLACE 0x70
-
-/*
- * When we insert 1st item on new page in INSERT, UPDATE, HOT_UPDATE,
- * or MULTI_INSERT, we can (and we do) restore entire page in redo
- */
-#define XLOG_HEAP_INIT_PAGE 0x01
/*
- * We ran out of opcodes, so heapam.c now has a second RmgrId. These opcodes
- * are associated with RM_HEAP2_ID, but are not logically different from
- * the ones above associated with RM_HEAP_ID.
+ * The HEAP2 designation is historical.
*
* There's no difference between XLOG_HEAP2_PRUNE_ON_ACCESS,
* XLOG_HEAP2_PRUNE_VACUUM_SCAN and XLOG_HEAP2_PRUNE_VACUUM_CLEANUP records.
* They have separate opcodes just for debugging and analysis purposes, to
* indicate why the WAL record was emitted.
*/
-#define XLOG_HEAP2_REWRITE 0x00
-#define XLOG_HEAP2_PRUNE_ON_ACCESS 0x10
-#define XLOG_HEAP2_PRUNE_VACUUM_SCAN 0x20
-#define XLOG_HEAP2_PRUNE_VACUUM_CLEANUP 0x30
-#define XLOG_HEAP2_VISIBLE 0x40
-#define XLOG_HEAP2_MULTI_INSERT 0x50
-#define XLOG_HEAP2_LOCK_UPDATED 0x60
-#define XLOG_HEAP2_NEW_CID 0x70
+#define XLOG_HEAP2_REWRITE 0x80
+#define XLOG_HEAP2_PRUNE_ON_ACCESS 0x90
+#define XLOG_HEAP2_PRUNE_VACUUM_SCAN 0xA0
+#define XLOG_HEAP2_PRUNE_VACUUM_CLEANUP 0xB0
+#define XLOG_HEAP2_VISIBLE 0xC0
+#define XLOG_HEAP2_MULTI_INSERT 0xD0
+#define XLOG_HEAP2_LOCK_UPDATED 0xE0
+#define XLOG_HEAP2_NEW_CID 0xF0
+
+/*
+ * When we insert 1st item on new page in INSERT, UPDATE, HOT_UPDATE,
+ * or MULTI_INSERT, we can (and we do) restore entire page in redo
+ */
+#define XLOG_HEAP_INIT_PAGE 0x01
/*
* xl_heap_insert/xl_heap_multi_insert flag values, 8 bits are available.
@@ -485,9 +483,6 @@ extern void heap_redo(XLogReaderState *record);
extern void heap_desc(StringInfo buf, XLogReaderState *record);
extern const char *heap_identify(uint8 info);
extern void heap_mask(char *pagedata, BlockNumber blkno);
-extern void heap2_redo(XLogReaderState *record);
-extern void heap2_desc(StringInfo buf, XLogReaderState *record);
-extern const char *heap2_identify(uint8 info);
extern void heap_xlog_logical_rewrite(XLogReaderState *r);
extern XLogRecPtr log_heap_visible(Relation rel, Buffer heap_buffer,
diff --git a/src/include/access/rmgrlist.h b/src/include/access/rmgrlist.h
index 8e7fc9db877..e2bc93468a4 100644
--- a/src/include/access/rmgrlist.h
+++ b/src/include/access/rmgrlist.h
@@ -34,7 +34,6 @@ PG_RMGR(RM_TBLSPC_ID, "Tablespace", tblspc_redo, tblspc_desc, tblspc_identify, N
PG_RMGR(RM_MULTIXACT_ID, "MultiXact", multixact_redo, multixact_desc, multixact_identify, NULL, NULL, NULL, NULL)
PG_RMGR(RM_RELMAP_ID, "RelMap", relmap_redo, relmap_desc, relmap_identify, NULL, NULL, NULL, NULL)
PG_RMGR(RM_STANDBY_ID, "Standby", standby_redo, standby_desc, standby_identify, NULL, NULL, NULL, standby_decode)
-PG_RMGR(RM_HEAP2_ID, "Heap2", heap2_redo, heap2_desc, heap2_identify, NULL, NULL, heap_mask, heap2_decode)
PG_RMGR(RM_HEAP_ID, "Heap", heap_redo, heap_desc, heap_identify, NULL, NULL, heap_mask, heap_decode)
PG_RMGR(RM_BTREE_ID, "Btree", btree_redo, btree_desc, btree_identify, btree_xlog_startup, btree_xlog_cleanup, btree_mask, NULL)
PG_RMGR(RM_HASH_ID, "Hash", hash_redo, hash_desc, hash_identify, NULL, NULL, hash_mask, NULL)
--
2.51.0
v1-0001-Split-XLogRecord.info-into-separate-members.patchapplication/x-patch; name=v1-0001-Split-XLogRecord.info-into-separate-members.patchDownload
From 4c76d0a3a6242eae605f605f7ba229581832c0d1 Mon Sep 17 00:00:00 2001
From: John Naylor <john.naylor@postgresql.org>
Date: Wed, 1 Oct 2025 17:09:06 +0700
Subject: [PATCH v1 1/4] Split XLogRecord.info into separate members
"info" is now rmgr-specific, including record type and optional flags.
"geninfo" is for XLR_SPECIAL_REL_UPDATE, XLR_CHECK_CONSISTENCY, and
anything set internally by XLogInsertExtended.
XLogInsert is now a thin wrapper for XLogInsertExtended, which only
needs to be called when pasing geninfo flags.
---
contrib/pg_visibility/pg_visibility.c | 4 +--
contrib/pg_walinspect/pg_walinspect.c | 2 +-
src/backend/access/transam/xact.c | 10 ++++---
src/backend/access/transam/xloginsert.c | 35 ++++++++++++++---------
src/backend/access/transam/xlogrecovery.c | 4 +--
src/backend/access/transam/xlogstats.c | 3 +-
src/backend/catalog/storage.c | 6 ++--
src/backend/commands/dbcommands.c | 16 +++++------
src/bin/pg_resetwal/pg_resetwal.c | 1 +
src/bin/pg_rewind/parsexlog.c | 7 +++--
src/bin/pg_waldump/pg_waldump.c | 2 +-
src/include/access/xloginsert.h | 1 +
src/include/access/xlogreader.h | 1 +
src/include/access/xlogrecord.h | 15 +++++++---
14 files changed, 64 insertions(+), 43 deletions(-)
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index d79ef35006b..3c5ff6be79e 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -429,8 +429,8 @@ pg_truncate_visibility_map(PG_FUNCTION_ARGS)
XLogBeginInsert();
XLogRegisterData(&xlrec, sizeof(xlrec));
- lsn = XLogInsert(RM_SMGR_ID,
- XLOG_SMGR_TRUNCATE | XLR_SPECIAL_REL_UPDATE);
+ lsn = XLogInsertExtended(RM_SMGR_ID,
+ XLOG_SMGR_TRUNCATE, XLR_SPECIAL_REL_UPDATE);
XLogFlush(lsn);
}
diff --git a/contrib/pg_walinspect/pg_walinspect.c b/contrib/pg_walinspect/pg_walinspect.c
index 0398ad82cec..da6a4f247ff 100644
--- a/contrib/pg_walinspect/pg_walinspect.c
+++ b/contrib/pg_walinspect/pg_walinspect.c
@@ -716,7 +716,7 @@ GetXLogSummaryStats(XLogStats *stats, ReturnSetInfo *rsinfo,
old_cxt = MemoryContextSwitchTo(tmp_cxt);
- /* the upper four bits in xl_info are the rmgr's */
+ /* the upper four bits in xl_info are the record type */
id = desc.rm_identify(rj << 4);
if (id == NULL)
id = psprintf("UNKNOWN (%x)", rj << 4);
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 2cf3d4e92b7..fc06474fc75 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -5842,6 +5842,7 @@ XactLogCommitRecord(TimestampTz commit_time,
xl_xact_twophase xl_twophase;
xl_xact_origin xl_origin;
uint8 info;
+ uint8 geninfo = 0;
Assert(CritSectionCount > 0);
@@ -5892,7 +5893,7 @@ XactLogCommitRecord(TimestampTz commit_time,
{
xl_xinfo.xinfo |= XACT_XINFO_HAS_RELFILELOCATORS;
xl_relfilelocators.nrels = nrels;
- info |= XLR_SPECIAL_REL_UPDATE;
+ geninfo |= XLR_SPECIAL_REL_UPDATE;
}
if (ndroppedstats > 0)
@@ -5985,7 +5986,7 @@ XactLogCommitRecord(TimestampTz commit_time,
/* we allow filtering by xacts */
XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
- return XLogInsert(RM_XACT_ID, info);
+ return XLogInsertExtended(RM_XACT_ID, info, geninfo);
}
/*
@@ -6012,6 +6013,7 @@ XactLogAbortRecord(TimestampTz abort_time,
xl_xact_origin xl_origin;
uint8 info;
+ uint8 geninfo = 0;
Assert(CritSectionCount > 0);
@@ -6041,7 +6043,7 @@ XactLogAbortRecord(TimestampTz abort_time,
{
xl_xinfo.xinfo |= XACT_XINFO_HAS_RELFILELOCATORS;
xl_relfilelocators.nrels = nrels;
- info |= XLR_SPECIAL_REL_UPDATE;
+ geninfo |= XLR_SPECIAL_REL_UPDATE;
}
if (ndroppedstats > 0)
@@ -6131,7 +6133,7 @@ XactLogAbortRecord(TimestampTz abort_time,
/* Include the replication origin */
XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
- return XLogInsert(RM_XACT_ID, info);
+ return XLogInsertExtended(RM_XACT_ID, info, geninfo);
}
/*
diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c
index c7571429e8e..2c0ffb46838 100644
--- a/src/backend/access/transam/xloginsert.c
+++ b/src/backend/access/transam/xloginsert.c
@@ -134,7 +134,7 @@ static bool begininsert_called = false;
/* Memory context to hold the registered buffer and data references. */
static MemoryContext xloginsert_cxt;
-static XLogRecData *XLogRecordAssemble(RmgrId rmid, uint8 info,
+static XLogRecData *XLogRecordAssemble(RmgrId rmid, uint8 info, uint8 geninfo,
XLogRecPtr RedoRecPtr, bool doPageWrites,
XLogRecPtr *fpw_lsn, int *num_fpi,
bool *topxid_included);
@@ -460,7 +460,7 @@ XLogSetRecordFlags(uint8 flags)
}
/*
- * Insert an XLOG record having the specified RMID and info bytes, with the
+ * Insert an XLOG record having the specified RMID, info and flag bytes, with the
* body of the record being the data and buffer references registered earlier
* with XLogRegister* calls.
*
@@ -471,7 +471,7 @@ XLogSetRecordFlags(uint8 flags)
* WAL rule "write the log before the data".)
*/
XLogRecPtr
-XLogInsert(RmgrId rmid, uint8 info)
+XLogInsertExtended(RmgrId rmid, uint8 info, uint8 geninfo)
{
XLogRecPtr EndPos;
@@ -480,14 +480,14 @@ XLogInsert(RmgrId rmid, uint8 info)
elog(ERROR, "XLogBeginInsert was not called");
/*
- * The caller can set rmgr bits, XLR_SPECIAL_REL_UPDATE and
- * XLR_CHECK_CONSISTENCY; the rest are reserved for use by me.
+ * The caller can set XLR_SPECIAL_REL_UPDATE and XLR_CHECK_CONSISTENCY;
+ * the rest are reserved for use by me.
*/
- if ((info & ~(XLR_RMGR_INFO_MASK |
- XLR_SPECIAL_REL_UPDATE |
- XLR_CHECK_CONSISTENCY)) != 0)
- elog(PANIC, "invalid xlog info mask %02X", info);
+ if ((geninfo & ~(XLR_SPECIAL_REL_UPDATE |
+ XLR_CHECK_CONSISTENCY)) != 0)
+ elog(PANIC, "invalid xlog geninfo mask %02X", geninfo);
+ /* WIP: need geninfo here? */
TRACE_POSTGRESQL_WAL_INSERT(rmid, info);
/*
@@ -517,7 +517,7 @@ XLogInsert(RmgrId rmid, uint8 info)
*/
GetFullPageWriteInfo(&RedoRecPtr, &doPageWrites);
- rdt = XLogRecordAssemble(rmid, info, RedoRecPtr, doPageWrites,
+ rdt = XLogRecordAssemble(rmid, info, geninfo, RedoRecPtr, doPageWrites,
&fpw_lsn, &num_fpi, &topxid_included);
EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags, num_fpi,
@@ -529,6 +529,14 @@ XLogInsert(RmgrId rmid, uint8 info)
return EndPos;
}
+/* Convenience wrapper for callers that don't pass "geninfo" */
+XLogRecPtr
+XLogInsert(RmgrId rmid, uint8 info)
+{
+ return XLogInsertExtended(rmid, info, 0);
+}
+
+
/*
* Simple wrapper to XLogInsert to insert a WAL record with elementary
* contents (only an int64 is supported as value currently).
@@ -557,7 +565,7 @@ XLogSimpleInsertInt64(RmgrId rmid, uint8 info, int64 value)
* current subtransaction.
*/
static XLogRecData *
-XLogRecordAssemble(RmgrId rmid, uint8 info,
+XLogRecordAssemble(RmgrId rmid, uint8 info, uint8 geninfo,
XLogRecPtr RedoRecPtr, bool doPageWrites,
XLogRecPtr *fpw_lsn, int *num_fpi, bool *topxid_included)
{
@@ -590,7 +598,7 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
* a record.
*/
if (wal_consistency_checking[rmid])
- info |= XLR_CHECK_CONSISTENCY;
+ geninfo |= XLR_CHECK_CONSISTENCY;
/*
* Make an rdata chain containing all the data portions of all block
@@ -656,7 +664,7 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
* If needs_backup is true or WAL checking is enabled for current
* resource manager, log a full-page write for the current block.
*/
- include_image = needs_backup || (info & XLR_CHECK_CONSISTENCY) != 0;
+ include_image = needs_backup || (geninfo & XLR_CHECK_CONSISTENCY) != 0;
if (include_image)
{
@@ -938,6 +946,7 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
rechdr->xl_xid = GetCurrentTransactionIdIfAny();
rechdr->xl_tot_len = (uint32) total_len;
rechdr->xl_info = info;
+ rechdr->xl_geninfo = geninfo;
rechdr->xl_rmid = rmid;
rechdr->xl_prev = InvalidXLogRecPtr;
rechdr->xl_crc = rdata_crc;
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index 52ff4d119e6..3e3aae0e47c 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -2006,7 +2006,7 @@ ApplyWalRecord(XLogReaderState *xlogreader, XLogRecord *record, TimeLineID *repl
* record are consistent with the existing pages. This check is done only
* if consistency check is enabled for this record.
*/
- if ((record->xl_info & XLR_CHECK_CONSISTENCY) != 0)
+ if ((record->xl_geninfo & XLR_CHECK_CONSISTENCY) != 0)
verifyBackupPageConsistency(xlogreader);
/* Pop the error context stack */
@@ -2483,7 +2483,7 @@ verifyBackupPageConsistency(XLogReaderState *record)
if (!XLogRecHasAnyBlockRefs(record))
return;
- Assert((XLogRecGetInfo(record) & XLR_CHECK_CONSISTENCY) != 0);
+ Assert((XLogRecGetGeninfo(record) & XLR_CHECK_CONSISTENCY) != 0);
for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
{
diff --git a/src/backend/access/transam/xlogstats.c b/src/backend/access/transam/xlogstats.c
index f92d9e13b17..4ddd204bd29 100644
--- a/src/backend/access/transam/xlogstats.c
+++ b/src/backend/access/transam/xlogstats.c
@@ -75,8 +75,7 @@ XLogRecStoreStats(XLogStats *stats, XLogReaderState *record)
/*
* Update per-record statistics, where the record is identified by a
* combination of the RmgrId and the four bits of the xl_info field that
- * are the rmgr's domain (resulting in sixteen possible entries per
- * RmgrId).
+ * are the record type (resulting in sixteen possible entries per RmgrId).
*/
recid = XLogRecGetInfo(record) >> 4;
diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c
index c58e9418ac3..829506296ed 100644
--- a/src/backend/catalog/storage.c
+++ b/src/backend/catalog/storage.c
@@ -196,7 +196,7 @@ log_smgrcreate(const RelFileLocator *rlocator, ForkNumber forkNum)
XLogBeginInsert();
XLogRegisterData(&xlrec, sizeof(xlrec));
- XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE | XLR_SPECIAL_REL_UPDATE);
+ XLogInsertExtended(RM_SMGR_ID, XLOG_SMGR_CREATE, XLR_SPECIAL_REL_UPDATE);
}
/*
@@ -400,8 +400,8 @@ RelationTruncate(Relation rel, BlockNumber nblocks)
XLogBeginInsert();
XLogRegisterData(&xlrec, sizeof(xlrec));
- lsn = XLogInsert(RM_SMGR_ID,
- XLOG_SMGR_TRUNCATE | XLR_SPECIAL_REL_UPDATE);
+ lsn = XLogInsertExtended(RM_SMGR_ID,
+ XLOG_SMGR_TRUNCATE, XLR_SPECIAL_REL_UPDATE);
/*
* Flush, because otherwise the truncation of the main relation might
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 2793fd83771..926c2d2e341 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -630,8 +630,8 @@ CreateDatabaseUsingFileCopy(Oid src_dboid, Oid dst_dboid, Oid src_tsid,
XLogRegisterData(&xlrec,
sizeof(xl_dbase_create_file_copy_rec));
- (void) XLogInsert(RM_DBASE_ID,
- XLOG_DBASE_CREATE_FILE_COPY | XLR_SPECIAL_REL_UPDATE);
+ (void) XLogInsertExtended(RM_DBASE_ID,
+ XLOG_DBASE_CREATE_FILE_COPY, XLR_SPECIAL_REL_UPDATE);
}
pfree(srcpath);
pfree(dstpath);
@@ -2213,8 +2213,8 @@ movedb(const char *dbname, const char *tblspcname)
XLogRegisterData(&xlrec,
sizeof(xl_dbase_create_file_copy_rec));
- (void) XLogInsert(RM_DBASE_ID,
- XLOG_DBASE_CREATE_FILE_COPY | XLR_SPECIAL_REL_UPDATE);
+ (void) XLogInsertExtended(RM_DBASE_ID,
+ XLOG_DBASE_CREATE_FILE_COPY, XLR_SPECIAL_REL_UPDATE);
}
/*
@@ -2309,8 +2309,8 @@ movedb(const char *dbname, const char *tblspcname)
XLogRegisterData(&xlrec, sizeof(xl_dbase_drop_rec));
XLogRegisterData(&src_tblspcoid, sizeof(Oid));
- (void) XLogInsert(RM_DBASE_ID,
- XLOG_DBASE_DROP | XLR_SPECIAL_REL_UPDATE);
+ (void) XLogInsertExtended(RM_DBASE_ID,
+ XLOG_DBASE_DROP, XLR_SPECIAL_REL_UPDATE);
}
/* Now it's safe to release the database lock */
@@ -3067,8 +3067,8 @@ remove_dbtablespaces(Oid db_id)
XLogRegisterData(&xlrec, MinSizeOfDbaseDropRec);
XLogRegisterData(tablespace_ids, ntblspc * sizeof(Oid));
- (void) XLogInsert(RM_DBASE_ID,
- XLOG_DBASE_DROP | XLR_SPECIAL_REL_UPDATE);
+ (void) XLogInsertExtended(RM_DBASE_ID,
+ XLOG_DBASE_DROP, XLR_SPECIAL_REL_UPDATE);
}
list_free(ltblspc);
diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c
index 7a4e4eb9570..ac4a7a7fe71 100644
--- a/src/bin/pg_resetwal/pg_resetwal.c
+++ b/src/bin/pg_resetwal/pg_resetwal.c
@@ -1132,6 +1132,7 @@ WriteEmptyXLOG(void)
record->xl_xid = InvalidTransactionId;
record->xl_tot_len = SizeOfXLogRecord + SizeOfXLogRecordDataHeaderShort + sizeof(CheckPoint);
record->xl_info = XLOG_CHECKPOINT_SHUTDOWN;
+ record->xl_geninfo = 0;
record->xl_rmid = RM_XLOG_ID;
recptr += SizeOfXLogRecord;
diff --git a/src/bin/pg_rewind/parsexlog.c b/src/bin/pg_rewind/parsexlog.c
index 8f4b282c6b1..dbc1c50b100 100644
--- a/src/bin/pg_rewind/parsexlog.c
+++ b/src/bin/pg_rewind/parsexlog.c
@@ -392,6 +392,7 @@ extractPageInfo(XLogReaderState *record)
RmgrId rmid = XLogRecGetRmid(record);
uint8 info = XLogRecGetInfo(record);
uint8 rminfo = info & ~XLR_INFO_MASK;
+ uint8 geninfo = XLogRecGetGeninfo(record);
/* Is this a special record type that I recognize? */
@@ -451,7 +452,7 @@ extractPageInfo(XLogReaderState *record)
* source.
*/
}
- else if (info & XLR_SPECIAL_REL_UPDATE)
+ else if (geninfo & XLR_SPECIAL_REL_UPDATE)
{
/*
* This record type modifies a relation file in some special way, but
@@ -459,9 +460,9 @@ extractPageInfo(XLogReaderState *record)
* track that change.
*/
pg_fatal("WAL record modifies a relation, but record type is not recognized:\n"
- "lsn: %X/%08X, rmid: %d, rmgr: %s, info: %02X",
+ "lsn: %X/%08X, rmid: %d, rmgr: %s, geninfo: %02X",
LSN_FORMAT_ARGS(record->ReadRecPtr),
- rmid, RmgrName(rmid), info);
+ rmid, RmgrName(rmid), geninfo);
}
for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c
index 13d3ec2f5be..98cd57fa117 100644
--- a/src/bin/pg_waldump/pg_waldump.c
+++ b/src/bin/pg_waldump/pg_waldump.c
@@ -711,7 +711,7 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogStats *stats)
if (count == 0)
continue;
- /* the upper four bits in xl_info are the rmgr's */
+ /* the upper four bits in xl_info are the record type */
id = desc->rm_identify(rj << 4);
if (id == NULL)
id = psprintf("UNKNOWN (%x)", rj << 4);
diff --git a/src/include/access/xloginsert.h b/src/include/access/xloginsert.h
index d6a71415d4f..f2cb2c4bbac 100644
--- a/src/include/access/xloginsert.h
+++ b/src/include/access/xloginsert.h
@@ -44,6 +44,7 @@
extern void XLogBeginInsert(void);
extern void XLogSetRecordFlags(uint8 flags);
extern XLogRecPtr XLogInsert(RmgrId rmid, uint8 info);
+extern XLogRecPtr XLogInsertExtended(RmgrId rmid, uint8 info, uint8 geninfo);
extern XLogRecPtr XLogSimpleInsertInt64(RmgrId rmid, uint8 info, int64 value);
extern void XLogEnsureRecordSpace(int max_block_id, int ndatas);
extern void XLogRegisterData(const void *data, uint32 len);
diff --git a/src/include/access/xlogreader.h b/src/include/access/xlogreader.h
index 9738462d3c9..6faf02e840f 100644
--- a/src/include/access/xlogreader.h
+++ b/src/include/access/xlogreader.h
@@ -408,6 +408,7 @@ extern bool DecodeXLogRecord(XLogReaderState *state,
#define XLogRecGetTotalLen(decoder) ((decoder)->record->header.xl_tot_len)
#define XLogRecGetPrev(decoder) ((decoder)->record->header.xl_prev)
#define XLogRecGetInfo(decoder) ((decoder)->record->header.xl_info)
+#define XLogRecGetGeninfo(decoder) ((decoder)->record->header.xl_geninfo)
#define XLogRecGetRmid(decoder) ((decoder)->record->header.xl_rmid)
#define XLogRecGetXid(decoder) ((decoder)->record->header.xl_xid)
#define XLogRecGetOrigin(decoder) ((decoder)->record->record_origin)
diff --git a/src/include/access/xlogrecord.h b/src/include/access/xlogrecord.h
index a06833ce0a3..9a587bc5b01 100644
--- a/src/include/access/xlogrecord.h
+++ b/src/include/access/xlogrecord.h
@@ -45,7 +45,15 @@ typedef struct XLogRecord
XLogRecPtr xl_prev; /* ptr to previous record in log */
uint8 xl_info; /* flag bits, see below */
RmgrId xl_rmid; /* resource manager for this record */
- /* 2 bytes of padding here, initialize to zero */
+
+ /*
+ * The XLR_SPECIAL_REL_UPDATE and XLR_CHECK_CONSISTENCY bits can be passed
+ * by XLogInsertExtended caller. The rest are set internally by
+ * XLogInsertExtended.
+ */
+ uint8 xl_geninfo;
+
+ /* 1 byte of padding here, initialize to zero */
pg_crc32c xl_crc; /* CRC for this record */
/* XLogRecordBlockHeaders and XLogRecordDataHeader follow, no padding */
@@ -55,9 +63,8 @@ typedef struct XLogRecord
#define SizeOfXLogRecord (offsetof(XLogRecord, xl_crc) + sizeof(pg_crc32c))
/*
- * The high 4 bits in xl_info may be used freely by rmgr. The
- * XLR_SPECIAL_REL_UPDATE and XLR_CHECK_CONSISTENCY bits can be passed by
- * XLogInsert caller. The rest are set internally by XLogInsert.
+ * All of xl_info may be used freely by rmgr. The high 4 bits are the
+ * record type and the rest are optional flag bits.
*/
#define XLR_INFO_MASK 0x0F
#define XLR_RMGR_INFO_MASK 0xF0
--
2.51.0
On Mon, Oct 06, 2025 at 04:04:00PM +0700, John Naylor wrote:
0004: get rid of RM_HEAP2_ID. This was simple once the prerequisites
were in place. All of the HEAP2_* macros keep the same name and only
differ in value. Heap rmgr is completely full so it might be good to
increase to 5 bits for the record type to give it some breathing room.
I haven't looked at the patch set in depth yet, but +1 to adding some
breathing room if possible. In my early attempts at partial HOT, I had to
add a third heap rmgr because the two existing ones were already full.
It'd be nice to avoid going back to multiple heap rmgrs.
--
nathan
On Mon, Oct 06, 2025 at 04:04:00PM +0700, John Naylor wrote:
Making the XLogRecord header nicer has been proposed several times
[1][2][3]. In [2], Robert wondered if with 2 bytes of xl_info, we
could get rid of the separate xl_xact_info. There could be other
possibilities as well, but I haven't done anything in that direction.
The attached just gets as far as the modest goal mentioned in the
subject.
Splitting the generic flags by stealing one of the padding bytes in
XLogRecord sounds like an improvement on clarity grounds, at least.
0001: Split xl_info into xl_info for rmgr-specific info and xl_geninfo
for generic flags. I used the XLogInsertExtended() idea from one of
Matthias's patches in [3], but wrote the rest a different way to keep
churn small.
Removing XLR_RMGR_INFO_MASK becomes natural here, causing
XLR_INFO_MASK to also become unnecessary. One benefit of this
proposal is that we would not need a heap3 once the opcodes are
completely full for the two existing ones, which should be fine enough
for many years to come. I have noticed after writing this sentence
that it is what Matthias has done in his patch to separate these
fields. More code churn, but I'd be in favor of fully biting the
bullet and do as Matthias is proposing, getting rid of XLR_INFO_MASK
entirely if we let the full byte at disposal of the RMGRs.
0002 and 0003: To simplify the rmgrs that have an opmask and separate
flag (I saw two obvious ones but I didn't make sure they were the only
ones), reserve the high 4 bits of xl_info for the "record type" (I see
xlogstats.c calls it a "recid", so that might be a better name) and
the lower 4 bits for the flag. Using the same scheme everywhere
simplifies things.
XLR_REC_TYPE_MASK and XLR_REC_FLAGS_MASK seem a bit confusing to me.
This is an attempt to generalize a rule that two RMGRs have been using
locally. In short I am not sure what we are gaining here, coming back
to the previous point that we should get rid of XLR_INFO_MASK, IMO.
That's the kind of rules I'd leave up to the RMGRs, so this does not
like a necessary abstraction, at least IMO.
There are new XLR_* masks whose names reflect their new purpose
better, but they are the same values as the old ones. XLR_INFO_MASK is
kept around for compatibility, but it doesn't do anything useful since
the rmgr has the full byte available. In order for ~XLR_INFO_MASK to
become a no-op on a full byte, XLR_INFO_MASK has to be zero, which
looks very odd. Removing it would be clearer, at the cost of more
churn.
I think that it would be weird to keep XLR_INFO_MASK for compatibility
reasons, with it set at 0, so I would bite the bullet and just get rid
of it entirely. There was not so long ago a proposal to get entirely
rid of most the footprint of XLR_INFO_MASK in the code, switching to
an equivalent macro:
/messages/by-id/CAGjhLkNYhNfbhsZhR_sEJ=1VqJmFCzx1BVfWWZ0+it2ucqG-pw@mail.gmail.com
That's also what you are doing here..
0004: get rid of RM_HEAP2_ID. This was simple once the prerequisites
were in place. All of the HEAP2_* macros keep the same name and only
differ in value. Heap rmgr is completely full so it might be good to
increase to 5 bits for the record type to give it some breathing room.
This is making an increase in size a prerequisite for anybody who
would want to add a new heap record, which is a problem because this
is pushing this responsibility to the one who would like to add a new
record. In short, I am not sure that we will ever get rid of heap2,
but I see a pretty good set of arguments to do things so as we'll
never need an equivalent for heap3, or an extra RMGR for any of the
existing RMGRs that use already all of their opcodes (Gin seems to be
using 8 opcodes currently, as one example, so it's full).
--
Michael
On Thu, Oct 9, 2025 at 1:43 PM Michael Paquier <michael@paquier.xyz> wrote:
0001: Split xl_info into xl_info for rmgr-specific info and xl_geninfo
for generic flags. I used the XLogInsertExtended() idea from one of
Matthias's patches in [3], but wrote the rest a different way to keep
churn small.Removing XLR_RMGR_INFO_MASK becomes natural here, causing
XLR_INFO_MASK to also become unnecessary. One benefit of this
proposal is that we would not need a heap3 once the opcodes are
completely full for the two existing ones, which should be fine enough
for many years to come. I have noticed after writing this sentence
that it is what Matthias has done in his patch to separate these
fields. More code churn, but I'd be in favor of fully biting the
bullet and do as Matthias is proposing, getting rid of XLR_INFO_MASK
entirely if we let the full byte at disposal of the RMGRs.
Okay.
0002 and 0003: To simplify the rmgrs that have an opmask and separate
flag (I saw two obvious ones but I didn't make sure they were the only
ones), reserve the high 4 bits of xl_info for the "record type" (I see
xlogstats.c calls it a "recid", so that might be a better name) and
the lower 4 bits for the flag. Using the same scheme everywhere
simplifies things.XLR_REC_TYPE_MASK and XLR_REC_FLAGS_MASK seem a bit confusing to me.
This is an attempt to generalize a rule that two RMGRs have been using
locally. In short I am not sure what we are gaining here, coming back
to the previous point that we should get rid of XLR_INFO_MASK, IMO.
That's the kind of rules I'd leave up to the RMGRs, so this does not
like a necessary abstraction, at least IMO.
Leaving that up to the rmgr makes sense. One consideration I didn't
mention was for xlogstats.c -- "record_stats[rmid][recid]" would get
16x larger if recid could take up the full byte. Maybe that's
harmless, but I didn't want to assume. Any thoughts on that?
--
John Naylor
Amazon Web Services
On Thu, Oct 09, 2025 at 03:15:11PM +0700, John Naylor wrote:
Leaving that up to the rmgr makes sense. One consideration I didn't
mention was for xlogstats.c -- "record_stats[rmid][recid]" would get
16x larger if recid could take up the full byte. Maybe that's
harmless, but I didn't want to assume. Any thoughts on that?
I've missed this interaction, thanks for mentioning it. XLogStats is
a local state that's only used by pg_walinspect and pg_waldump, so
this extra memory consumed does worry me much; this stuff interacts
with no critical paths.
--
Michael
On Fri, Oct 10, 2025 at 9:47 AM Michael Paquier <michael@paquier.xyz> wrote:
On Thu, Oct 09, 2025 at 03:15:11PM +0700, John Naylor wrote:
Leaving that up to the rmgr makes sense. One consideration I didn't
mention was for xlogstats.c -- "record_stats[rmid][recid]" would get
16x larger if recid could take up the full byte. Maybe that's
harmless, but I didn't want to assume. Any thoughts on that?I've missed this interaction, thanks for mentioning it. XLogStats is
a local state that's only used by pg_walinspect and pg_waldump, so
this extra memory consumed does worry me much; this stuff interacts
with no critical paths.
Okay, v2 gets rid of the general info mask (split out into 0002 for
readability) and leaves alone the RMGR-specific masks (i.e. leaves out
v1 0002/3). It runs fine with installcheck while streaming to a
standby with wal_consistency_checking. I've also left out the removal
of HEAP2 for now. Giving existing RMGRs more breathing room seems like
a better motivator, going by Nathan's comment and yours.
It's worth thinking about backward compatibility if we did go as far
as a 2-byte xl_info (upthread: to allow more RMGR-specific flags, so
e.g. XACT wouldn't need xl_xact_info) In that case, we'd probably
still want a convention that only the lowest byte can contain the
record type. XLogStats could simply assume that in most cases. For
XACT 8 flags in the upper byte still won't be enough, and it will
still need to have its own opcode mask, but that's no worse than the
situation we have already.
--
John Naylor
Amazon Web Services
Attachments:
v2-0001-Split-XLogRecord.xl_info-into-separate-members.patchapplication/x-patch; name=v2-0001-Split-XLogRecord.xl_info-into-separate-members.patchDownload
From b58209171b2f81470f6a1c4f0529767a72cda1d2 Mon Sep 17 00:00:00 2001
From: John Naylor <john.naylor@postgresql.org>
Date: Wed, 1 Oct 2025 17:09:06 +0700
Subject: [PATCH v2 1/2] Split XLogRecord.xl_info into separate members
"xl_info" is for use by the RMGR only. Each RMGR now has the full
byte available and can decide how to specify record type and how to
store any optional flags. This should prevent RMGRs from ever again
needing to spill over into a separate RMGR ID. It is now possible to
get rid of HEAP2, but that is left for possible future work.
"xl_geninfo" is the home for XLR_SPECIAL_REL_UPDATE,
XLR_CHECK_CONSISTENCY, and anything reserved internally by
XLogInsertExtended.
XLogInsert is now a thin wrapper around XLogInsertExtended, The
latter only needs to be called when pasing xl_geninfo flags.
The idea has been proposed in the past by Andres Freund, Robert Haas,
and Matthias van de Meent. Credit to Matthias van de Meent for
XLogInsertExtended.
Bump XLOG_PAGE_MAGIC
Reviewed-by: Michael Paquier <michael@paquier.xyz>
---
contrib/pg_visibility/pg_visibility.c | 4 +--
contrib/pg_walinspect/pg_walinspect.c | 5 ++--
src/backend/access/transam/xact.c | 10 ++++---
src/backend/access/transam/xloginsert.c | 34 +++++++++++++++--------
src/backend/access/transam/xlogrecovery.c | 4 +--
src/backend/access/transam/xlogstats.c | 13 ++++-----
src/backend/catalog/storage.c | 6 ++--
src/backend/commands/dbcommands.c | 16 +++++------
src/bin/pg_resetwal/pg_resetwal.c | 1 +
src/bin/pg_rewind/parsexlog.c | 7 +++--
src/bin/pg_waldump/pg_waldump.c | 5 ++--
src/include/access/xact.h | 2 +-
src/include/access/xlog_internal.h | 2 +-
src/include/access/xloginsert.h | 1 +
src/include/access/xlogreader.h | 1 +
src/include/access/xlogrecord.h | 17 ++++++------
src/include/access/xlogstats.h | 2 +-
17 files changed, 71 insertions(+), 59 deletions(-)
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index d79ef35006b..3c5ff6be79e 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -429,8 +429,8 @@ pg_truncate_visibility_map(PG_FUNCTION_ARGS)
XLogBeginInsert();
XLogRegisterData(&xlrec, sizeof(xlrec));
- lsn = XLogInsert(RM_SMGR_ID,
- XLOG_SMGR_TRUNCATE | XLR_SPECIAL_REL_UPDATE);
+ lsn = XLogInsertExtended(RM_SMGR_ID,
+ XLOG_SMGR_TRUNCATE, XLR_SPECIAL_REL_UPDATE);
XLogFlush(lsn);
}
diff --git a/contrib/pg_walinspect/pg_walinspect.c b/contrib/pg_walinspect/pg_walinspect.c
index 501cea8fc1a..21444bc5bc3 100644
--- a/contrib/pg_walinspect/pg_walinspect.c
+++ b/contrib/pg_walinspect/pg_walinspect.c
@@ -717,10 +717,9 @@ GetXLogSummaryStats(XLogStats *stats, ReturnSetInfo *rsinfo,
old_cxt = MemoryContextSwitchTo(tmp_cxt);
- /* the upper four bits in xl_info are the rmgr's */
- id = desc.rm_identify(rj << 4);
+ id = desc.rm_identify(rj);
if (id == NULL)
- id = psprintf("UNKNOWN (%x)", rj << 4);
+ id = psprintf("UNKNOWN (%x)", rj);
FillXLogStatsRow(psprintf("%s/%s", desc.rm_name, id), count,
total_count, rec_len, total_rec_len, fpi_len,
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 2cf3d4e92b7..fc06474fc75 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -5842,6 +5842,7 @@ XactLogCommitRecord(TimestampTz commit_time,
xl_xact_twophase xl_twophase;
xl_xact_origin xl_origin;
uint8 info;
+ uint8 geninfo = 0;
Assert(CritSectionCount > 0);
@@ -5892,7 +5893,7 @@ XactLogCommitRecord(TimestampTz commit_time,
{
xl_xinfo.xinfo |= XACT_XINFO_HAS_RELFILELOCATORS;
xl_relfilelocators.nrels = nrels;
- info |= XLR_SPECIAL_REL_UPDATE;
+ geninfo |= XLR_SPECIAL_REL_UPDATE;
}
if (ndroppedstats > 0)
@@ -5985,7 +5986,7 @@ XactLogCommitRecord(TimestampTz commit_time,
/* we allow filtering by xacts */
XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
- return XLogInsert(RM_XACT_ID, info);
+ return XLogInsertExtended(RM_XACT_ID, info, geninfo);
}
/*
@@ -6012,6 +6013,7 @@ XactLogAbortRecord(TimestampTz abort_time,
xl_xact_origin xl_origin;
uint8 info;
+ uint8 geninfo = 0;
Assert(CritSectionCount > 0);
@@ -6041,7 +6043,7 @@ XactLogAbortRecord(TimestampTz abort_time,
{
xl_xinfo.xinfo |= XACT_XINFO_HAS_RELFILELOCATORS;
xl_relfilelocators.nrels = nrels;
- info |= XLR_SPECIAL_REL_UPDATE;
+ geninfo |= XLR_SPECIAL_REL_UPDATE;
}
if (ndroppedstats > 0)
@@ -6131,7 +6133,7 @@ XactLogAbortRecord(TimestampTz abort_time,
/* Include the replication origin */
XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
- return XLogInsert(RM_XACT_ID, info);
+ return XLogInsertExtended(RM_XACT_ID, info, geninfo);
}
/*
diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c
index 496e0fa4ac6..89fdf45ebb6 100644
--- a/src/backend/access/transam/xloginsert.c
+++ b/src/backend/access/transam/xloginsert.c
@@ -134,7 +134,7 @@ static bool begininsert_called = false;
/* Memory context to hold the registered buffer and data references. */
static MemoryContext xloginsert_cxt;
-static XLogRecData *XLogRecordAssemble(RmgrId rmid, uint8 info,
+static XLogRecData *XLogRecordAssemble(RmgrId rmid, uint8 info, uint8 geninfo,
XLogRecPtr RedoRecPtr, bool doPageWrites,
XLogRecPtr *fpw_lsn, int *num_fpi,
bool *topxid_included);
@@ -472,7 +472,7 @@ XLogSetRecordFlags(uint8 flags)
* WAL rule "write the log before the data".)
*/
XLogRecPtr
-XLogInsert(RmgrId rmid, uint8 info)
+XLogInsertExtended(RmgrId rmid, uint8 info, uint8 geninfo)
{
XLogRecPtr EndPos;
@@ -481,14 +481,14 @@ XLogInsert(RmgrId rmid, uint8 info)
elog(ERROR, "XLogBeginInsert was not called");
/*
- * The caller can set rmgr bits, XLR_SPECIAL_REL_UPDATE and
- * XLR_CHECK_CONSISTENCY; the rest are reserved for use by me.
+ * The caller can set XLR_SPECIAL_REL_UPDATE and XLR_CHECK_CONSISTENCY;
+ * the rest are reserved for use by me.
*/
- if ((info & ~(XLR_RMGR_INFO_MASK |
- XLR_SPECIAL_REL_UPDATE |
- XLR_CHECK_CONSISTENCY)) != 0)
- elog(PANIC, "invalid xlog info mask %02X", info);
+ if ((geninfo & ~(XLR_SPECIAL_REL_UPDATE |
+ XLR_CHECK_CONSISTENCY)) != 0)
+ elog(PANIC, "invalid xlog geninfo mask %02X", geninfo);
+ /* WIP: need geninfo here? */
TRACE_POSTGRESQL_WAL_INSERT(rmid, info);
/*
@@ -518,7 +518,7 @@ XLogInsert(RmgrId rmid, uint8 info)
*/
GetFullPageWriteInfo(&RedoRecPtr, &doPageWrites);
- rdt = XLogRecordAssemble(rmid, info, RedoRecPtr, doPageWrites,
+ rdt = XLogRecordAssemble(rmid, info, geninfo, RedoRecPtr, doPageWrites,
&fpw_lsn, &num_fpi, &topxid_included);
EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags, num_fpi,
@@ -530,6 +530,15 @@ XLogInsert(RmgrId rmid, uint8 info)
return EndPos;
}
+/* Convenience wrapper for callers that don't pass "geninfo" */
+/* WIP: should this be an inline function in xloginsert.h? */
+XLogRecPtr
+XLogInsert(RmgrId rmid, uint8 info)
+{
+ return XLogInsertExtended(rmid, info, 0);
+}
+
+
/*
* Simple wrapper to XLogInsert to insert a WAL record with elementary
* contents (only an int64 is supported as value currently).
@@ -558,7 +567,7 @@ XLogSimpleInsertInt64(RmgrId rmid, uint8 info, int64 value)
* current subtransaction.
*/
static XLogRecData *
-XLogRecordAssemble(RmgrId rmid, uint8 info,
+XLogRecordAssemble(RmgrId rmid, uint8 info, uint8 geninfo,
XLogRecPtr RedoRecPtr, bool doPageWrites,
XLogRecPtr *fpw_lsn, int *num_fpi, bool *topxid_included)
{
@@ -591,7 +600,7 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
* a record.
*/
if (wal_consistency_checking[rmid])
- info |= XLR_CHECK_CONSISTENCY;
+ geninfo |= XLR_CHECK_CONSISTENCY;
/*
* Make an rdata chain containing all the data portions of all block
@@ -657,7 +666,7 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
* If needs_backup is true or WAL checking is enabled for current
* resource manager, log a full-page write for the current block.
*/
- include_image = needs_backup || (info & XLR_CHECK_CONSISTENCY) != 0;
+ include_image = needs_backup || (geninfo & XLR_CHECK_CONSISTENCY) != 0;
if (include_image)
{
@@ -939,6 +948,7 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
rechdr->xl_xid = GetCurrentTransactionIdIfAny();
rechdr->xl_tot_len = (uint32) total_len;
rechdr->xl_info = info;
+ rechdr->xl_geninfo = geninfo;
rechdr->xl_rmid = rmid;
rechdr->xl_prev = InvalidXLogRecPtr;
rechdr->xl_crc = rdata_crc;
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index 52ff4d119e6..3e3aae0e47c 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -2006,7 +2006,7 @@ ApplyWalRecord(XLogReaderState *xlogreader, XLogRecord *record, TimeLineID *repl
* record are consistent with the existing pages. This check is done only
* if consistency check is enabled for this record.
*/
- if ((record->xl_info & XLR_CHECK_CONSISTENCY) != 0)
+ if ((record->xl_geninfo & XLR_CHECK_CONSISTENCY) != 0)
verifyBackupPageConsistency(xlogreader);
/* Pop the error context stack */
@@ -2483,7 +2483,7 @@ verifyBackupPageConsistency(XLogReaderState *record)
if (!XLogRecHasAnyBlockRefs(record))
return;
- Assert((XLogRecGetInfo(record) & XLR_CHECK_CONSISTENCY) != 0);
+ Assert((XLogRecGetGeninfo(record) & XLR_CHECK_CONSISTENCY) != 0);
for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
{
diff --git a/src/backend/access/transam/xlogstats.c b/src/backend/access/transam/xlogstats.c
index 85963a6ac29..07bb1f00cc6 100644
--- a/src/backend/access/transam/xlogstats.c
+++ b/src/backend/access/transam/xlogstats.c
@@ -74,18 +74,15 @@ XLogRecStoreStats(XLogStats *stats, XLogReaderState *record)
/*
* Update per-record statistics, where the record is identified by a
- * combination of the RmgrId and the four bits of the xl_info field that
- * are the rmgr's domain (resulting in sixteen possible entries per
- * RmgrId).
+ * combination of the RmgrId and the record type.
*/
- recid = XLogRecGetInfo(record) >> 4;
+ recid = XLogRecGetInfo(record);
/*
- * XACT records need to be handled differently. Those records use the
- * first bit of those four bits for an optional flag variable and the
- * following three bits for the opcode. We filter opcode out of xl_info
- * and use it as the identifier of the record.
+ * XACT records need to be handled differently. Those records use three
+ * bits for the opcode and the rest for optional flag variables. We filter
+ * opcode out of xl_info and use it as the identifier of the record.
*/
if (rmid == RM_XACT_ID)
recid &= 0x07;
diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c
index c58e9418ac3..829506296ed 100644
--- a/src/backend/catalog/storage.c
+++ b/src/backend/catalog/storage.c
@@ -196,7 +196,7 @@ log_smgrcreate(const RelFileLocator *rlocator, ForkNumber forkNum)
XLogBeginInsert();
XLogRegisterData(&xlrec, sizeof(xlrec));
- XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE | XLR_SPECIAL_REL_UPDATE);
+ XLogInsertExtended(RM_SMGR_ID, XLOG_SMGR_CREATE, XLR_SPECIAL_REL_UPDATE);
}
/*
@@ -400,8 +400,8 @@ RelationTruncate(Relation rel, BlockNumber nblocks)
XLogBeginInsert();
XLogRegisterData(&xlrec, sizeof(xlrec));
- lsn = XLogInsert(RM_SMGR_ID,
- XLOG_SMGR_TRUNCATE | XLR_SPECIAL_REL_UPDATE);
+ lsn = XLogInsertExtended(RM_SMGR_ID,
+ XLOG_SMGR_TRUNCATE, XLR_SPECIAL_REL_UPDATE);
/*
* Flush, because otherwise the truncation of the main relation might
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 4d65e8c46c2..9ed7266b9b3 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -630,8 +630,8 @@ CreateDatabaseUsingFileCopy(Oid src_dboid, Oid dst_dboid, Oid src_tsid,
XLogRegisterData(&xlrec,
sizeof(xl_dbase_create_file_copy_rec));
- (void) XLogInsert(RM_DBASE_ID,
- XLOG_DBASE_CREATE_FILE_COPY | XLR_SPECIAL_REL_UPDATE);
+ (void) XLogInsertExtended(RM_DBASE_ID,
+ XLOG_DBASE_CREATE_FILE_COPY, XLR_SPECIAL_REL_UPDATE);
}
pfree(srcpath);
pfree(dstpath);
@@ -2213,8 +2213,8 @@ movedb(const char *dbname, const char *tblspcname)
XLogRegisterData(&xlrec,
sizeof(xl_dbase_create_file_copy_rec));
- (void) XLogInsert(RM_DBASE_ID,
- XLOG_DBASE_CREATE_FILE_COPY | XLR_SPECIAL_REL_UPDATE);
+ (void) XLogInsertExtended(RM_DBASE_ID,
+ XLOG_DBASE_CREATE_FILE_COPY, XLR_SPECIAL_REL_UPDATE);
}
/*
@@ -2309,8 +2309,8 @@ movedb(const char *dbname, const char *tblspcname)
XLogRegisterData(&xlrec, sizeof(xl_dbase_drop_rec));
XLogRegisterData(&src_tblspcoid, sizeof(Oid));
- (void) XLogInsert(RM_DBASE_ID,
- XLOG_DBASE_DROP | XLR_SPECIAL_REL_UPDATE);
+ (void) XLogInsertExtended(RM_DBASE_ID,
+ XLOG_DBASE_DROP, XLR_SPECIAL_REL_UPDATE);
}
/* Now it's safe to release the database lock */
@@ -3067,8 +3067,8 @@ remove_dbtablespaces(Oid db_id)
XLogRegisterData(&xlrec, MinSizeOfDbaseDropRec);
XLogRegisterData(tablespace_ids, ntblspc * sizeof(Oid));
- (void) XLogInsert(RM_DBASE_ID,
- XLOG_DBASE_DROP | XLR_SPECIAL_REL_UPDATE);
+ (void) XLogInsertExtended(RM_DBASE_ID,
+ XLOG_DBASE_DROP, XLR_SPECIAL_REL_UPDATE);
}
list_free(ltblspc);
diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c
index 7a4e4eb9570..ac4a7a7fe71 100644
--- a/src/bin/pg_resetwal/pg_resetwal.c
+++ b/src/bin/pg_resetwal/pg_resetwal.c
@@ -1132,6 +1132,7 @@ WriteEmptyXLOG(void)
record->xl_xid = InvalidTransactionId;
record->xl_tot_len = SizeOfXLogRecord + SizeOfXLogRecordDataHeaderShort + sizeof(CheckPoint);
record->xl_info = XLOG_CHECKPOINT_SHUTDOWN;
+ record->xl_geninfo = 0;
record->xl_rmid = RM_XLOG_ID;
recptr += SizeOfXLogRecord;
diff --git a/src/bin/pg_rewind/parsexlog.c b/src/bin/pg_rewind/parsexlog.c
index 8f4b282c6b1..953ca8a1a8d 100644
--- a/src/bin/pg_rewind/parsexlog.c
+++ b/src/bin/pg_rewind/parsexlog.c
@@ -392,6 +392,7 @@ extractPageInfo(XLogReaderState *record)
RmgrId rmid = XLogRecGetRmid(record);
uint8 info = XLogRecGetInfo(record);
uint8 rminfo = info & ~XLR_INFO_MASK;
+ uint8 geninfo = XLogRecGetGeninfo(record);
/* Is this a special record type that I recognize? */
@@ -451,7 +452,7 @@ extractPageInfo(XLogReaderState *record)
* source.
*/
}
- else if (info & XLR_SPECIAL_REL_UPDATE)
+ else if (geninfo & XLR_SPECIAL_REL_UPDATE)
{
/*
* This record type modifies a relation file in some special way, but
@@ -459,9 +460,9 @@ extractPageInfo(XLogReaderState *record)
* track that change.
*/
pg_fatal("WAL record modifies a relation, but record type is not recognized:\n"
- "lsn: %X/%08X, rmid: %d, rmgr: %s, info: %02X",
+ "lsn: %X/%08X, rmid: %d, rmgr: %s, info: %02X, geninfo: %02X",
LSN_FORMAT_ARGS(record->ReadRecPtr),
- rmid, RmgrName(rmid), info);
+ rmid, RmgrName(rmid), rminfo, geninfo);
}
for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c
index 13d3ec2f5be..74b878a240a 100644
--- a/src/bin/pg_waldump/pg_waldump.c
+++ b/src/bin/pg_waldump/pg_waldump.c
@@ -711,10 +711,9 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogStats *stats)
if (count == 0)
continue;
- /* the upper four bits in xl_info are the rmgr's */
- id = desc->rm_identify(rj << 4);
+ id = desc->rm_identify(rj);
if (id == NULL)
- id = psprintf("UNKNOWN (%x)", rj << 4);
+ id = psprintf("UNKNOWN (%x)", rj);
XLogDumpStatsRow(psprintf("%s/%s", desc->rm_name, id),
count, total_count, rec_len, total_rec_len,
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 4528e51829e..523cf814ee0 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -164,7 +164,7 @@ typedef struct SavedTransactionCharacteristics
*/
/*
- * XLOG allows to store some information in high 4 bits of log record xl_info
+ * XLOG allows storing some information in the log record's xl_info
* field. We use 3 for the opcode, and one about an optional flag variable.
*/
#define XLOG_XACT_COMMIT 0x00
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index cc06fc29ab2..34deb2fe5f0 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -31,7 +31,7 @@
/*
* Each page of XLOG file has a header like this:
*/
-#define XLOG_PAGE_MAGIC 0xD118 /* can be used as WAL version indicator */
+#define XLOG_PAGE_MAGIC 0xD119 /* can be used as WAL version indicator */
typedef struct XLogPageHeaderData
{
diff --git a/src/include/access/xloginsert.h b/src/include/access/xloginsert.h
index d6a71415d4f..f2cb2c4bbac 100644
--- a/src/include/access/xloginsert.h
+++ b/src/include/access/xloginsert.h
@@ -44,6 +44,7 @@
extern void XLogBeginInsert(void);
extern void XLogSetRecordFlags(uint8 flags);
extern XLogRecPtr XLogInsert(RmgrId rmid, uint8 info);
+extern XLogRecPtr XLogInsertExtended(RmgrId rmid, uint8 info, uint8 geninfo);
extern XLogRecPtr XLogSimpleInsertInt64(RmgrId rmid, uint8 info, int64 value);
extern void XLogEnsureRecordSpace(int max_block_id, int ndatas);
extern void XLogRegisterData(const void *data, uint32 len);
diff --git a/src/include/access/xlogreader.h b/src/include/access/xlogreader.h
index 9738462d3c9..6faf02e840f 100644
--- a/src/include/access/xlogreader.h
+++ b/src/include/access/xlogreader.h
@@ -408,6 +408,7 @@ extern bool DecodeXLogRecord(XLogReaderState *state,
#define XLogRecGetTotalLen(decoder) ((decoder)->record->header.xl_tot_len)
#define XLogRecGetPrev(decoder) ((decoder)->record->header.xl_prev)
#define XLogRecGetInfo(decoder) ((decoder)->record->header.xl_info)
+#define XLogRecGetGeninfo(decoder) ((decoder)->record->header.xl_geninfo)
#define XLogRecGetRmid(decoder) ((decoder)->record->header.xl_rmid)
#define XLogRecGetXid(decoder) ((decoder)->record->header.xl_xid)
#define XLogRecGetOrigin(decoder) ((decoder)->record->record_origin)
diff --git a/src/include/access/xlogrecord.h b/src/include/access/xlogrecord.h
index a06833ce0a3..d3855f7314e 100644
--- a/src/include/access/xlogrecord.h
+++ b/src/include/access/xlogrecord.h
@@ -43,9 +43,10 @@ typedef struct XLogRecord
uint32 xl_tot_len; /* total len of entire record */
TransactionId xl_xid; /* xact id */
XLogRecPtr xl_prev; /* ptr to previous record in log */
- uint8 xl_info; /* flag bits, see below */
+ uint8 xl_info; /* RMGR-specific info */
RmgrId xl_rmid; /* resource manager for this record */
- /* 2 bytes of padding here, initialize to zero */
+ uint8 xl_geninfo; /* flag bits, see below */
+ /* 1 byte of padding here, initialize to zero */
pg_crc32c xl_crc; /* CRC for this record */
/* XLogRecordBlockHeaders and XLogRecordDataHeader follow, no padding */
@@ -54,13 +55,7 @@ typedef struct XLogRecord
#define SizeOfXLogRecord (offsetof(XLogRecord, xl_crc) + sizeof(pg_crc32c))
-/*
- * The high 4 bits in xl_info may be used freely by rmgr. The
- * XLR_SPECIAL_REL_UPDATE and XLR_CHECK_CONSISTENCY bits can be passed by
- * XLogInsert caller. The rest are set internally by XLogInsert.
- */
#define XLR_INFO_MASK 0x0F
-#define XLR_RMGR_INFO_MASK 0xF0
/*
* XLogReader needs to allocate all the data of a WAL record in a single
@@ -73,6 +68,12 @@ typedef struct XLogRecord
*/
#define XLogRecordMaxSize (1020 * 1024 * 1024)
+/*
+ * The XLR_SPECIAL_REL_UPDATE and XLR_CHECK_CONSISTENCY bits destined for
+ * xl_geninfo can be passed to XLogInsertExtended. The rest are set
+ * internally by XLogInsertExtended.
+ */
+
/*
* If a WAL record modifies any relation files, in ways not covered by the
* usual block references, this flag is set. This is not used for anything
diff --git a/src/include/access/xlogstats.h b/src/include/access/xlogstats.h
index 6ec6670d44c..ca84d39f5ab 100644
--- a/src/include/access/xlogstats.h
+++ b/src/include/access/xlogstats.h
@@ -16,7 +16,7 @@
#include "access/rmgr.h"
#include "access/xlogreader.h"
-#define MAX_XLINFO_TYPES 16
+#define MAX_XLINFO_TYPES 256
typedef struct XLogRecStats
{
--
2.51.0
v2-0002-Remove-XLR_INFO_MASK.patchapplication/x-patch; name=v2-0002-Remove-XLR_INFO_MASK.patchDownload
From f89886f2baea15efb1ada32a3d6e01d6a5022c90 Mon Sep 17 00:00:00 2001
From: John Naylor <john.naylor@postgresql.org>
Date: Mon, 13 Oct 2025 15:29:53 +0700
Subject: [PATCH v2 2/2] Remove XLR_INFO_MASK
XXX Separate for visibility, to be squashed
---
contrib/pg_walinspect/pg_walinspect.c | 4 ++--
src/backend/access/brin/brin_xlog.c | 2 +-
src/backend/access/gin/ginxlog.c | 2 +-
src/backend/access/gist/gistxlog.c | 2 +-
src/backend/access/hash/hash_xlog.c | 2 +-
src/backend/access/heap/heapam_xlog.c | 4 ++--
src/backend/access/nbtree/nbtxlog.c | 2 +-
src/backend/access/rmgrdesc/brindesc.c | 4 ++--
src/backend/access/rmgrdesc/clogdesc.c | 4 ++--
src/backend/access/rmgrdesc/committsdesc.c | 2 +-
src/backend/access/rmgrdesc/dbasedesc.c | 4 ++--
src/backend/access/rmgrdesc/gindesc.c | 4 ++--
src/backend/access/rmgrdesc/gistdesc.c | 4 ++--
src/backend/access/rmgrdesc/hashdesc.c | 4 ++--
src/backend/access/rmgrdesc/heapdesc.c | 8 ++++----
src/backend/access/rmgrdesc/logicalmsgdesc.c | 4 ++--
src/backend/access/rmgrdesc/mxactdesc.c | 4 ++--
src/backend/access/rmgrdesc/nbtdesc.c | 4 ++--
src/backend/access/rmgrdesc/relmapdesc.c | 4 ++--
src/backend/access/rmgrdesc/replorigindesc.c | 2 +-
src/backend/access/rmgrdesc/seqdesc.c | 4 ++--
src/backend/access/rmgrdesc/smgrdesc.c | 4 ++--
src/backend/access/rmgrdesc/spgdesc.c | 4 ++--
src/backend/access/rmgrdesc/standbydesc.c | 4 ++--
src/backend/access/rmgrdesc/tblspcdesc.c | 4 ++--
src/backend/access/rmgrdesc/xlogdesc.c | 4 ++--
src/backend/access/spgist/spgxlog.c | 2 +-
src/backend/access/transam/clog.c | 2 +-
src/backend/access/transam/commit_ts.c | 2 +-
src/backend/access/transam/multixact.c | 2 +-
src/backend/access/transam/xlog.c | 4 ++--
src/backend/access/transam/xlogprefetcher.c | 2 +-
src/backend/access/transam/xlogreader.c | 2 +-
src/backend/access/transam/xlogrecovery.c | 18 +++++++++---------
src/backend/catalog/storage.c | 2 +-
src/backend/commands/dbcommands.c | 2 +-
src/backend/commands/sequence.c | 2 +-
src/backend/commands/tablespace.c | 2 +-
src/backend/postmaster/walsummarizer.c | 8 ++++----
src/backend/replication/logical/decode.c | 6 +++---
src/backend/replication/logical/message.c | 2 +-
src/backend/replication/logical/origin.c | 2 +-
src/backend/storage/ipc/standby.c | 2 +-
src/backend/utils/cache/relmapper.c | 2 +-
src/bin/pg_rewind/parsexlog.c | 5 ++---
src/bin/pg_waldump/pg_waldump.c | 2 +-
src/include/access/xlogrecord.h | 2 --
.../test_custom_rmgrs/test_custom_rmgrs.c | 6 +++---
48 files changed, 85 insertions(+), 88 deletions(-)
diff --git a/contrib/pg_walinspect/pg_walinspect.c b/contrib/pg_walinspect/pg_walinspect.c
index 21444bc5bc3..2deb367c623 100644
--- a/contrib/pg_walinspect/pg_walinspect.c
+++ b/contrib/pg_walinspect/pg_walinspect.c
@@ -204,7 +204,7 @@ GetWALRecordInfo(XLogReaderState *record, Datum *values,
record_type = desc.rm_identify(XLogRecGetInfo(record));
if (record_type == NULL)
- record_type = psprintf("UNKNOWN (%x)", XLogRecGetInfo(record) & ~XLR_INFO_MASK);
+ record_type = psprintf("UNKNOWN (%x)", XLogRecGetInfo(record));
initStringInfo(&rec_desc);
desc.rm_desc(&rec_desc, record);
@@ -267,7 +267,7 @@ GetWALBlockInfo(FunctionCallInfo fcinfo, XLogReaderState *record,
if (record_type == NULL)
record_type = psprintf("UNKNOWN (%x)",
- XLogRecGetInfo(record) & ~XLR_INFO_MASK);
+ XLogRecGetInfo(record));
initStringInfo(&rec_desc);
desc.rm_desc(&rec_desc, record);
diff --git a/src/backend/access/brin/brin_xlog.c b/src/backend/access/brin/brin_xlog.c
index 55348140fad..0cac80f20e4 100644
--- a/src/backend/access/brin/brin_xlog.c
+++ b/src/backend/access/brin/brin_xlog.c
@@ -308,7 +308,7 @@ brin_xlog_desummarize_page(XLogReaderState *record)
void
brin_redo(XLogReaderState *record)
{
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
switch (info & XLOG_BRIN_OPMASK)
{
diff --git a/src/backend/access/gin/ginxlog.c b/src/backend/access/gin/ginxlog.c
index fa293ee79d5..3f80a12fd36 100644
--- a/src/backend/access/gin/ginxlog.c
+++ b/src/backend/access/gin/ginxlog.c
@@ -724,7 +724,7 @@ ginRedoDeleteListPages(XLogReaderState *record)
void
gin_redo(XLogReaderState *record)
{
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
MemoryContext oldCtx;
/*
diff --git a/src/backend/access/gist/gistxlog.c b/src/backend/access/gist/gistxlog.c
index 42fee1f0764..7cb0d119c20 100644
--- a/src/backend/access/gist/gistxlog.c
+++ b/src/backend/access/gist/gistxlog.c
@@ -396,7 +396,7 @@ gistRedoPageReuse(XLogReaderState *record)
void
gist_redo(XLogReaderState *record)
{
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
MemoryContext oldCxt;
/*
diff --git a/src/backend/access/hash/hash_xlog.c b/src/backend/access/hash/hash_xlog.c
index d963a0c3702..e19186c87d8 100644
--- a/src/backend/access/hash/hash_xlog.c
+++ b/src/backend/access/hash/hash_xlog.c
@@ -1066,7 +1066,7 @@ hash_xlog_vacuum_one_page(XLogReaderState *record)
void
hash_redo(XLogReaderState *record)
{
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
switch (info)
{
diff --git a/src/backend/access/heap/heapam_xlog.c b/src/backend/access/heap/heapam_xlog.c
index 230d9888793..e74273672ef 100644
--- a/src/backend/access/heap/heapam_xlog.c
+++ b/src/backend/access/heap/heapam_xlog.c
@@ -1300,7 +1300,7 @@ heap_xlog_inplace(XLogReaderState *record)
void
heap_redo(XLogReaderState *record)
{
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
/*
* These operations don't overwrite MVCC data so no conflict processing is
@@ -1346,7 +1346,7 @@ heap_redo(XLogReaderState *record)
void
heap2_redo(XLogReaderState *record)
{
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
switch (info & XLOG_HEAP_OPMASK)
{
diff --git a/src/backend/access/nbtree/nbtxlog.c b/src/backend/access/nbtree/nbtxlog.c
index 69ea668bb0d..1e1a7cc4953 100644
--- a/src/backend/access/nbtree/nbtxlog.c
+++ b/src/backend/access/nbtree/nbtxlog.c
@@ -1017,7 +1017,7 @@ btree_xlog_reuse_page(XLogReaderState *record)
void
btree_redo(XLogReaderState *record)
{
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
MemoryContext oldCtx;
oldCtx = MemoryContextSwitchTo(opCtx);
diff --git a/src/backend/access/rmgrdesc/brindesc.c b/src/backend/access/rmgrdesc/brindesc.c
index 9fc0bfe2a52..b9782208d95 100644
--- a/src/backend/access/rmgrdesc/brindesc.c
+++ b/src/backend/access/rmgrdesc/brindesc.c
@@ -20,7 +20,7 @@ void
brin_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
info &= XLOG_BRIN_OPMASK;
if (info == XLOG_BRIN_CREATE_INDEX)
@@ -75,7 +75,7 @@ brin_identify(uint8 info)
{
const char *id = NULL;
- switch (info & ~XLR_INFO_MASK)
+ switch (info)
{
case XLOG_BRIN_CREATE_INDEX:
id = "CREATE_INDEX";
diff --git a/src/backend/access/rmgrdesc/clogdesc.c b/src/backend/access/rmgrdesc/clogdesc.c
index 41bf28dcfd0..7c466d98086 100644
--- a/src/backend/access/rmgrdesc/clogdesc.c
+++ b/src/backend/access/rmgrdesc/clogdesc.c
@@ -21,7 +21,7 @@ void
clog_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
if (info == CLOG_ZEROPAGE)
{
@@ -45,7 +45,7 @@ clog_identify(uint8 info)
{
const char *id = NULL;
- switch (info & ~XLR_INFO_MASK)
+ switch (info)
{
case CLOG_ZEROPAGE:
id = "ZEROPAGE";
diff --git a/src/backend/access/rmgrdesc/committsdesc.c b/src/backend/access/rmgrdesc/committsdesc.c
index a6ab9dd78de..47152924987 100644
--- a/src/backend/access/rmgrdesc/committsdesc.c
+++ b/src/backend/access/rmgrdesc/committsdesc.c
@@ -21,7 +21,7 @@ void
commit_ts_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
if (info == COMMIT_TS_ZEROPAGE)
{
diff --git a/src/backend/access/rmgrdesc/dbasedesc.c b/src/backend/access/rmgrdesc/dbasedesc.c
index 4224c5673ff..530ab285595 100644
--- a/src/backend/access/rmgrdesc/dbasedesc.c
+++ b/src/backend/access/rmgrdesc/dbasedesc.c
@@ -22,7 +22,7 @@ void
dbase_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
if (info == XLOG_DBASE_CREATE_FILE_COPY)
{
@@ -58,7 +58,7 @@ dbase_identify(uint8 info)
{
const char *id = NULL;
- switch (info & ~XLR_INFO_MASK)
+ switch (info)
{
case XLOG_DBASE_CREATE_FILE_COPY:
id = "CREATE_FILE_COPY";
diff --git a/src/backend/access/rmgrdesc/gindesc.c b/src/backend/access/rmgrdesc/gindesc.c
index 075c4a0ae93..5a1c72a3d3a 100644
--- a/src/backend/access/rmgrdesc/gindesc.c
+++ b/src/backend/access/rmgrdesc/gindesc.c
@@ -72,7 +72,7 @@ void
gin_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
switch (info)
{
@@ -187,7 +187,7 @@ gin_identify(uint8 info)
{
const char *id = NULL;
- switch (info & ~XLR_INFO_MASK)
+ switch (info)
{
case XLOG_GIN_CREATE_PTREE:
id = "CREATE_PTREE";
diff --git a/src/backend/access/rmgrdesc/gistdesc.c b/src/backend/access/rmgrdesc/gistdesc.c
index a2b84e898f9..931cc1f6e90 100644
--- a/src/backend/access/rmgrdesc/gistdesc.c
+++ b/src/backend/access/rmgrdesc/gistdesc.c
@@ -61,7 +61,7 @@ void
gist_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
switch (info)
{
@@ -91,7 +91,7 @@ gist_identify(uint8 info)
{
const char *id = NULL;
- switch (info & ~XLR_INFO_MASK)
+ switch (info)
{
case XLOG_GIST_PAGE_UPDATE:
id = "PAGE_UPDATE";
diff --git a/src/backend/access/rmgrdesc/hashdesc.c b/src/backend/access/rmgrdesc/hashdesc.c
index 2ee5332452f..5cdd6b31f76 100644
--- a/src/backend/access/rmgrdesc/hashdesc.c
+++ b/src/backend/access/rmgrdesc/hashdesc.c
@@ -20,7 +20,7 @@ void
hash_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
switch (info)
{
@@ -132,7 +132,7 @@ hash_identify(uint8 info)
{
const char *id = NULL;
- switch (info & ~XLR_INFO_MASK)
+ switch (info)
{
case XLOG_HASH_INIT_META_PAGE:
id = "INIT_META_PAGE";
diff --git a/src/backend/access/rmgrdesc/heapdesc.c b/src/backend/access/rmgrdesc/heapdesc.c
index ca26d1f0ed1..08f4b7234a3 100644
--- a/src/backend/access/rmgrdesc/heapdesc.c
+++ b/src/backend/access/rmgrdesc/heapdesc.c
@@ -185,7 +185,7 @@ void
heap_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
info &= XLOG_HEAP_OPMASK;
if (info == XLOG_HEAP_INSERT)
@@ -265,7 +265,7 @@ void
heap2_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
info &= XLOG_HEAP_OPMASK;
if (info == XLOG_HEAP2_PRUNE_ON_ACCESS ||
@@ -405,7 +405,7 @@ heap_identify(uint8 info)
{
const char *id = NULL;
- switch (info & ~XLR_INFO_MASK)
+ switch (info)
{
case XLOG_HEAP_INSERT:
id = "INSERT";
@@ -450,7 +450,7 @@ heap2_identify(uint8 info)
{
const char *id = NULL;
- switch (info & ~XLR_INFO_MASK)
+ switch (info)
{
case XLOG_HEAP2_PRUNE_ON_ACCESS:
id = "PRUNE_ON_ACCESS";
diff --git a/src/backend/access/rmgrdesc/logicalmsgdesc.c b/src/backend/access/rmgrdesc/logicalmsgdesc.c
index 1c8c99f19f8..1b81c9dbfb1 100644
--- a/src/backend/access/rmgrdesc/logicalmsgdesc.c
+++ b/src/backend/access/rmgrdesc/logicalmsgdesc.c
@@ -19,7 +19,7 @@ void
logicalmsg_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
if (info == XLOG_LOGICAL_MESSAGE)
{
@@ -45,7 +45,7 @@ logicalmsg_desc(StringInfo buf, XLogReaderState *record)
const char *
logicalmsg_identify(uint8 info)
{
- if ((info & ~XLR_INFO_MASK) == XLOG_LOGICAL_MESSAGE)
+ if (info == XLOG_LOGICAL_MESSAGE)
return "MESSAGE";
return NULL;
diff --git a/src/backend/access/rmgrdesc/mxactdesc.c b/src/backend/access/rmgrdesc/mxactdesc.c
index 3ca0582db36..11eec402443 100644
--- a/src/backend/access/rmgrdesc/mxactdesc.c
+++ b/src/backend/access/rmgrdesc/mxactdesc.c
@@ -50,7 +50,7 @@ void
multixact_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE ||
info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
@@ -85,7 +85,7 @@ multixact_identify(uint8 info)
{
const char *id = NULL;
- switch (info & ~XLR_INFO_MASK)
+ switch (info)
{
case XLOG_MULTIXACT_ZERO_OFF_PAGE:
id = "ZERO_OFF_PAGE";
diff --git a/src/backend/access/rmgrdesc/nbtdesc.c b/src/backend/access/rmgrdesc/nbtdesc.c
index c05d19ab007..5ad5742af19 100644
--- a/src/backend/access/rmgrdesc/nbtdesc.c
+++ b/src/backend/access/rmgrdesc/nbtdesc.c
@@ -24,7 +24,7 @@ void
btree_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
switch (info)
{
@@ -140,7 +140,7 @@ btree_identify(uint8 info)
{
const char *id = NULL;
- switch (info & ~XLR_INFO_MASK)
+ switch (info)
{
case XLOG_BTREE_INSERT_LEAF:
id = "INSERT_LEAF";
diff --git a/src/backend/access/rmgrdesc/relmapdesc.c b/src/backend/access/rmgrdesc/relmapdesc.c
index caf18460321..c518f88a87d 100644
--- a/src/backend/access/rmgrdesc/relmapdesc.c
+++ b/src/backend/access/rmgrdesc/relmapdesc.c
@@ -20,7 +20,7 @@ void
relmap_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
if (info == XLOG_RELMAP_UPDATE)
{
@@ -36,7 +36,7 @@ relmap_identify(uint8 info)
{
const char *id = NULL;
- switch (info & ~XLR_INFO_MASK)
+ switch (info)
{
case XLOG_RELMAP_UPDATE:
id = "UPDATE";
diff --git a/src/backend/access/rmgrdesc/replorigindesc.c b/src/backend/access/rmgrdesc/replorigindesc.c
index 35e3af2903e..285e64996f8 100644
--- a/src/backend/access/rmgrdesc/replorigindesc.c
+++ b/src/backend/access/rmgrdesc/replorigindesc.c
@@ -19,7 +19,7 @@ void
replorigin_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
switch (info)
{
diff --git a/src/backend/access/rmgrdesc/seqdesc.c b/src/backend/access/rmgrdesc/seqdesc.c
index 0d289d77fcf..475b22ed51e 100644
--- a/src/backend/access/rmgrdesc/seqdesc.c
+++ b/src/backend/access/rmgrdesc/seqdesc.c
@@ -21,7 +21,7 @@ void
seq_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
xl_seq_rec *xlrec = (xl_seq_rec *) rec;
if (info == XLOG_SEQ_LOG)
@@ -35,7 +35,7 @@ seq_identify(uint8 info)
{
const char *id = NULL;
- switch (info & ~XLR_INFO_MASK)
+ switch (info)
{
case XLOG_SEQ_LOG:
id = "LOG";
diff --git a/src/backend/access/rmgrdesc/smgrdesc.c b/src/backend/access/rmgrdesc/smgrdesc.c
index 4bb7fc79bce..4411d23a02b 100644
--- a/src/backend/access/rmgrdesc/smgrdesc.c
+++ b/src/backend/access/rmgrdesc/smgrdesc.c
@@ -21,7 +21,7 @@ void
smgr_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
if (info == XLOG_SMGR_CREATE)
{
@@ -45,7 +45,7 @@ smgr_identify(uint8 info)
{
const char *id = NULL;
- switch (info & ~XLR_INFO_MASK)
+ switch (info)
{
case XLOG_SMGR_CREATE:
id = "CREATE";
diff --git a/src/backend/access/rmgrdesc/spgdesc.c b/src/backend/access/rmgrdesc/spgdesc.c
index 72efedc5b40..5b2512a869f 100644
--- a/src/backend/access/rmgrdesc/spgdesc.c
+++ b/src/backend/access/rmgrdesc/spgdesc.c
@@ -20,7 +20,7 @@ void
spg_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
switch (info)
{
@@ -133,7 +133,7 @@ spg_identify(uint8 info)
{
const char *id = NULL;
- switch (info & ~XLR_INFO_MASK)
+ switch (info)
{
case XLOG_SPGIST_ADD_LEAF:
id = "ADD_LEAF";
diff --git a/src/backend/access/rmgrdesc/standbydesc.c b/src/backend/access/rmgrdesc/standbydesc.c
index 81eff5f31c4..ebe40ee7d7b 100644
--- a/src/backend/access/rmgrdesc/standbydesc.c
+++ b/src/backend/access/rmgrdesc/standbydesc.c
@@ -47,7 +47,7 @@ void
standby_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
if (info == XLOG_STANDBY_LOCK)
{
@@ -80,7 +80,7 @@ standby_identify(uint8 info)
{
const char *id = NULL;
- switch (info & ~XLR_INFO_MASK)
+ switch (info)
{
case XLOG_STANDBY_LOCK:
id = "LOCK";
diff --git a/src/backend/access/rmgrdesc/tblspcdesc.c b/src/backend/access/rmgrdesc/tblspcdesc.c
index 5d612b4232e..141ffbcd727 100644
--- a/src/backend/access/rmgrdesc/tblspcdesc.c
+++ b/src/backend/access/rmgrdesc/tblspcdesc.c
@@ -21,7 +21,7 @@ void
tblspc_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
if (info == XLOG_TBLSPC_CREATE)
{
@@ -42,7 +42,7 @@ tblspc_identify(uint8 info)
{
const char *id = NULL;
- switch (info & ~XLR_INFO_MASK)
+ switch (info)
{
case XLOG_TBLSPC_CREATE:
id = "CREATE";
diff --git a/src/backend/access/rmgrdesc/xlogdesc.c b/src/backend/access/rmgrdesc/xlogdesc.c
index cd6c2a2f650..aa9e9d7a04a 100644
--- a/src/backend/access/rmgrdesc/xlogdesc.c
+++ b/src/backend/access/rmgrdesc/xlogdesc.c
@@ -58,7 +58,7 @@ void
xlog_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
if (info == XLOG_CHECKPOINT_SHUTDOWN ||
info == XLOG_CHECKPOINT_ONLINE)
@@ -174,7 +174,7 @@ xlog_identify(uint8 info)
{
const char *id = NULL;
- switch (info & ~XLR_INFO_MASK)
+ switch (info)
{
case XLOG_CHECKPOINT_SHUTDOWN:
id = "CHECKPOINT_SHUTDOWN";
diff --git a/src/backend/access/spgist/spgxlog.c b/src/backend/access/spgist/spgxlog.c
index d4620c915d0..1d41bea17df 100644
--- a/src/backend/access/spgist/spgxlog.c
+++ b/src/backend/access/spgist/spgxlog.c
@@ -934,7 +934,7 @@ spgRedoVacuumRedirect(XLogReaderState *record)
void
spg_redo(XLogReaderState *record)
{
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
MemoryContext oldCxt;
oldCxt = MemoryContextSwitchTo(opCtx);
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index e80fbe109cf..7dd5b9e98c0 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -1061,7 +1061,7 @@ WriteTruncateXlogRec(int64 pageno, TransactionId oldestXact, Oid oldestXactDb)
void
clog_redo(XLogReaderState *record)
{
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
/* Backup blocks are not used in clog records */
Assert(!XLogRecHasAnyBlockRefs(record));
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 370b38e048b..d1f8a416299 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -982,7 +982,7 @@ WriteTruncateXlogRec(int64 pageno, TransactionId oldestXid)
void
commit_ts_redo(XLogReaderState *record)
{
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
/* Backup blocks are not used in commit_ts records */
Assert(!XLogRecHasAnyBlockRefs(record));
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 9d5f130af7e..5c3a5ee12b1 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -3329,7 +3329,7 @@ WriteMTruncateXlogRec(Oid oldestMultiDB,
void
multixact_redo(XLogReaderState *record)
{
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
/* Backup blocks are not used in multixact records */
Assert(!XLogRecHasAnyBlockRefs(record));
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index eceab341255..f513c5fdc22 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -755,7 +755,7 @@ XLogInsertRecord(XLogRecData *rdata,
pg_crc32c rdata_crc;
bool inserted;
XLogRecord *rechdr = (XLogRecord *) rdata->data;
- uint8 info = rechdr->xl_info & ~XLR_INFO_MASK;
+ uint8 info = rechdr->xl_info;
WalInsertClass class = WALINSERT_NORMAL;
XLogRecPtr StartPos;
XLogRecPtr EndPos;
@@ -8284,7 +8284,7 @@ UpdateFullPageWrites(void)
void
xlog_redo(XLogReaderState *record)
{
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
XLogRecPtr lsn = record->EndRecPtr;
/*
diff --git a/src/backend/access/transam/xlogprefetcher.c b/src/backend/access/transam/xlogprefetcher.c
index ed3aacabc98..7e2b754001c 100644
--- a/src/backend/access/transam/xlogprefetcher.c
+++ b/src/backend/access/transam/xlogprefetcher.c
@@ -530,7 +530,7 @@ XLogPrefetcherNextBlock(uintptr_t pgsr_private, XLogRecPtr *lsn)
if (replaying_lsn < record->lsn)
{
uint8 rmid = record->header.xl_rmid;
- uint8 record_type = record->header.xl_info & ~XLR_INFO_MASK;
+ uint8 record_type = record->header.xl_info;
if (rmid == RM_XLOG_ID)
{
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index dcc8d4f9c1b..5d17038249e 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -874,7 +874,7 @@ restart:
* Special processing if it's an XLOG SWITCH record
*/
if (record->xl_rmid == RM_XLOG_ID &&
- (record->xl_info & ~XLR_INFO_MASK) == XLOG_SWITCH)
+ record->xl_info == XLOG_SWITCH)
{
/* Pretend it extends to end of segment */
state->NextRecPtr += state->segcxt.ws_segsize - 1;
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index 3e3aae0e47c..5ff52062b82 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -635,7 +635,7 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
if (record != NULL)
{
memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint));
- wasShutdown = ((record->xl_info & ~XLR_INFO_MASK) == XLOG_CHECKPOINT_SHUTDOWN);
+ wasShutdown = (record->xl_info == XLOG_CHECKPOINT_SHUTDOWN);
ereport(DEBUG1,
errmsg_internal("checkpoint record is at %X/%08X",
LSN_FORMAT_ARGS(CheckPointLoc)));
@@ -803,7 +803,7 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
LSN_FORMAT_ARGS(CheckPointLoc)));
}
memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint));
- wasShutdown = ((record->xl_info & ~XLR_INFO_MASK) == XLOG_CHECKPOINT_SHUTDOWN);
+ wasShutdown = (record->xl_info == XLOG_CHECKPOINT_SHUTDOWN);
}
if (ArchiveRecoveryRequested)
@@ -1722,7 +1722,7 @@ PerformWalRecovery(void)
* record.
*/
if (record->xl_rmid != RM_XLOG_ID ||
- (record->xl_info & ~XLR_INFO_MASK) != XLOG_CHECKPOINT_REDO)
+ record->xl_info != XLOG_CHECKPOINT_REDO)
ereport(FATAL,
errmsg("unexpected record type found at redo point %X/%08X",
LSN_FORMAT_ARGS(xlogreader->ReadRecPtr)));
@@ -1944,7 +1944,7 @@ ApplyWalRecord(XLogReaderState *xlogreader, XLogRecord *record, TimeLineID *repl
{
TimeLineID newReplayTLI = *replayTLI;
TimeLineID prevReplayTLI = *replayTLI;
- uint8 info = record->xl_info & ~XLR_INFO_MASK;
+ uint8 info = record->xl_info;
if (info == XLOG_CHECKPOINT_SHUTDOWN)
{
@@ -2082,7 +2082,7 @@ ApplyWalRecord(XLogReaderState *xlogreader, XLogRecord *record, TimeLineID *repl
static void
xlogrecovery_redo(XLogReaderState *record, TimeLineID replayTLI)
{
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
XLogRecPtr lsn = record->EndRecPtr;
Assert(XLogRecGetRmid(record) == RM_XLOG_ID);
@@ -2318,7 +2318,7 @@ xlog_outdesc(StringInfo buf, XLogReaderState *record)
id = rmgr.rm_identify(info);
if (id == NULL)
- appendStringInfo(buf, "UNKNOWN (%X): ", info & ~XLR_INFO_MASK);
+ appendStringInfo(buf, "UNKNOWN (%X): ", info);
else
appendStringInfo(buf, "%s: ", id);
@@ -2438,7 +2438,7 @@ checkTimeLineSwitch(XLogRecPtr lsn, TimeLineID newTLI, TimeLineID prevTLI,
static bool
getRecordTimestamp(XLogReaderState *record, TimestampTz *recordXtime)
{
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
uint8 xact_info = info & XLOG_XACT_OPMASK;
uint8 rmid = XLogRecGetRmid(record);
@@ -2750,7 +2750,7 @@ recoveryStopsAfter(XLogReaderState *record)
if (!ArchiveRecoveryRequested)
return false;
- info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ info = XLogRecGetInfo(record);
rmid = XLogRecGetRmid(record);
/*
@@ -4100,7 +4100,7 @@ ReadCheckpointRecord(XLogPrefetcher *xlogprefetcher, XLogRecPtr RecPtr,
(errmsg("invalid resource manager ID in checkpoint record")));
return NULL;
}
- info = record->xl_info & ~XLR_INFO_MASK;
+ info = record->xl_info;
if (info != XLOG_CHECKPOINT_SHUTDOWN &&
info != XLOG_CHECKPOINT_ONLINE)
{
diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c
index 829506296ed..d2520ffa8be 100644
--- a/src/backend/catalog/storage.c
+++ b/src/backend/catalog/storage.c
@@ -981,7 +981,7 @@ void
smgr_redo(XLogReaderState *record)
{
XLogRecPtr lsn = record->EndRecPtr;
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
/* Backup blocks are not used in smgr records */
Assert(!XLogRecHasAnyBlockRefs(record));
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 9ed7266b9b3..c9380346faa 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -3285,7 +3285,7 @@ recovery_create_dbdir(char *path, bool only_tblspc)
void
dbase_redo(XLogReaderState *record)
{
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
/* Backup blocks are not used in dbase records */
Assert(!XLogRecHasAnyBlockRefs(record));
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index cf46a543364..4b23c7c205b 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1913,7 +1913,7 @@ void
seq_redo(XLogReaderState *record)
{
XLogRecPtr lsn = record->EndRecPtr;
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
Buffer buffer;
Page page;
Page localpage;
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index df31eace47a..01b4d8e5df0 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -1510,7 +1510,7 @@ get_tablespace_name(Oid spc_oid)
void
tblspc_redo(XLogReaderState *record)
{
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
/* Backup blocks are not used in tblspc records */
Assert(!XLogRecHasAnyBlockRefs(record));
diff --git a/src/backend/postmaster/walsummarizer.c b/src/backend/postmaster/walsummarizer.c
index e1f142f20c7..2f6fd9e928f 100644
--- a/src/backend/postmaster/walsummarizer.c
+++ b/src/backend/postmaster/walsummarizer.c
@@ -1248,7 +1248,7 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
static void
SummarizeDbaseRecord(XLogReaderState *xlogreader, BlockRefTable *brtab)
{
- uint8 info = XLogRecGetInfo(xlogreader) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(xlogreader);
/*
* We use relfilenode zero for a given database OID and tablespace OID to
@@ -1317,7 +1317,7 @@ SummarizeDbaseRecord(XLogReaderState *xlogreader, BlockRefTable *brtab)
static void
SummarizeSmgrRecord(XLogReaderState *xlogreader, BlockRefTable *brtab)
{
- uint8 info = XLogRecGetInfo(xlogreader) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(xlogreader);
if (info == XLOG_SMGR_CREATE)
{
@@ -1366,7 +1366,7 @@ SummarizeSmgrRecord(XLogReaderState *xlogreader, BlockRefTable *brtab)
static void
SummarizeXactRecord(XLogReaderState *xlogreader, BlockRefTable *brtab)
{
- uint8 info = XLogRecGetInfo(xlogreader) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(xlogreader);
uint8 xact_info = info & XLOG_XACT_OPMASK;
if (xact_info == XLOG_XACT_COMMIT ||
@@ -1426,7 +1426,7 @@ SummarizeXactRecord(XLogReaderState *xlogreader, BlockRefTable *brtab)
static bool
SummarizeXlogRecord(XLogReaderState *xlogreader, bool *new_fast_forward)
{
- uint8 info = XLogRecGetInfo(xlogreader) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(xlogreader);
int record_wal_level;
if (info == XLOG_CHECKPOINT_REDO)
diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c
index cc03f0706e9..d1b552e3990 100644
--- a/src/backend/replication/logical/decode.c
+++ b/src/backend/replication/logical/decode.c
@@ -129,7 +129,7 @@ void
xlog_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
{
SnapBuild *builder = ctx->snapshot_builder;
- uint8 info = XLogRecGetInfo(buf->record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(buf->record);
ReorderBufferProcessXid(ctx->reorder, XLogRecGetXid(buf->record),
buf->origptr);
@@ -360,7 +360,7 @@ standby_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
{
SnapBuild *builder = ctx->snapshot_builder;
XLogReaderState *r = buf->record;
- uint8 info = XLogRecGetInfo(r) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(r);
ReorderBufferProcessXid(ctx->reorder, XLogRecGetXid(r), buf->origptr);
@@ -597,7 +597,7 @@ logicalmsg_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
SnapBuild *builder = ctx->snapshot_builder;
XLogReaderState *r = buf->record;
TransactionId xid = XLogRecGetXid(r);
- uint8 info = XLogRecGetInfo(r) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(r);
RepOriginId origin_id = XLogRecGetOrigin(r);
Snapshot snapshot = NULL;
xl_logical_message *message;
diff --git a/src/backend/replication/logical/message.c b/src/backend/replication/logical/message.c
index ebc8454bad9..844e38d83d2 100644
--- a/src/backend/replication/logical/message.c
+++ b/src/backend/replication/logical/message.c
@@ -86,7 +86,7 @@ LogLogicalMessage(const char *prefix, const char *message, size_t size,
void
logicalmsg_redo(XLogReaderState *record)
{
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
if (info != XLOG_LOGICAL_MESSAGE)
elog(PANIC, "logicalmsg_redo: unknown op code %u", info);
diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c
index bcd5d9aad62..ee38ab55d09 100644
--- a/src/backend/replication/logical/origin.c
+++ b/src/backend/replication/logical/origin.c
@@ -849,7 +849,7 @@ StartupReplicationOrigin(void)
void
replorigin_redo(XLogReaderState *record)
{
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
switch (info)
{
diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c
index 4222bdab078..501de242f8b 100644
--- a/src/backend/storage/ipc/standby.c
+++ b/src/backend/storage/ipc/standby.c
@@ -1162,7 +1162,7 @@ StandbyReleaseOldLocks(TransactionId oldxid)
void
standby_redo(XLogReaderState *record)
{
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
/* Backup blocks are not used in standby records */
Assert(!XLogRecHasAnyBlockRefs(record));
diff --git a/src/backend/utils/cache/relmapper.c b/src/backend/utils/cache/relmapper.c
index abf89f0776e..d0afb932390 100644
--- a/src/backend/utils/cache/relmapper.c
+++ b/src/backend/utils/cache/relmapper.c
@@ -1095,7 +1095,7 @@ perform_relmap_update(bool shared, const RelMapFile *updates)
void
relmap_redo(XLogReaderState *record)
{
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
/* Backup blocks are not used in relmap records */
Assert(!XLogRecHasAnyBlockRefs(record));
diff --git a/src/bin/pg_rewind/parsexlog.c b/src/bin/pg_rewind/parsexlog.c
index 953ca8a1a8d..761f344d102 100644
--- a/src/bin/pg_rewind/parsexlog.c
+++ b/src/bin/pg_rewind/parsexlog.c
@@ -243,7 +243,7 @@ findLastCheckpoint(const char *datadir, XLogRecPtr forkptr, int tliIndex,
* be the latest checkpoint before WAL forked and not the checkpoint
* where the primary has been stopped to be rewound.
*/
- info = XLogRecGetInfo(xlogreader) & ~XLR_INFO_MASK;
+ info = XLogRecGetInfo(xlogreader);
if (searchptr < forkptr &&
XLogRecGetRmid(xlogreader) == RM_XLOG_ID &&
(info == XLOG_CHECKPOINT_SHUTDOWN ||
@@ -390,8 +390,7 @@ extractPageInfo(XLogReaderState *record)
{
int block_id;
RmgrId rmid = XLogRecGetRmid(record);
- uint8 info = XLogRecGetInfo(record);
- uint8 rminfo = info & ~XLR_INFO_MASK;
+ uint8 rminfo = XLogRecGetInfo(record);
uint8 geninfo = XLogRecGetGeninfo(record);
/* Is this a special record type that I recognize? */
diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c
index 74b878a240a..8d9111a7693 100644
--- a/src/bin/pg_waldump/pg_waldump.c
+++ b/src/bin/pg_waldump/pg_waldump.c
@@ -564,7 +564,7 @@ XLogDumpDisplayRecord(XLogDumpConfig *config, XLogReaderState *record)
id = desc->rm_identify(info);
if (id == NULL)
- printf("desc: UNKNOWN (%x) ", info & ~XLR_INFO_MASK);
+ printf("desc: UNKNOWN (%x) ", info);
else
printf("desc: %s ", id);
diff --git a/src/include/access/xlogrecord.h b/src/include/access/xlogrecord.h
index d3855f7314e..14a4967ce99 100644
--- a/src/include/access/xlogrecord.h
+++ b/src/include/access/xlogrecord.h
@@ -55,8 +55,6 @@ typedef struct XLogRecord
#define SizeOfXLogRecord (offsetof(XLogRecord, xl_crc) + sizeof(pg_crc32c))
-#define XLR_INFO_MASK 0x0F
-
/*
* XLogReader needs to allocate all the data of a WAL record in a single
* chunk. This means that a single XLogRecord cannot exceed MaxAllocSize
diff --git a/src/test/modules/test_custom_rmgrs/test_custom_rmgrs.c b/src/test/modules/test_custom_rmgrs/test_custom_rmgrs.c
index 1a424ad55a8..6153a426723 100644
--- a/src/test/modules/test_custom_rmgrs/test_custom_rmgrs.c
+++ b/src/test/modules/test_custom_rmgrs/test_custom_rmgrs.c
@@ -81,7 +81,7 @@ _PG_init(void)
void
testcustomrmgrs_redo(XLogReaderState *record)
{
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
if (info != XLOG_TEST_CUSTOM_RMGRS_MESSAGE)
elog(PANIC, "testcustomrmgrs_redo: unknown op code %u", info);
@@ -91,7 +91,7 @@ void
testcustomrmgrs_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
- uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
+ uint8 info = XLogRecGetInfo(record);
if (info == XLOG_TEST_CUSTOM_RMGRS_MESSAGE)
{
@@ -105,7 +105,7 @@ testcustomrmgrs_desc(StringInfo buf, XLogReaderState *record)
const char *
testcustomrmgrs_identify(uint8 info)
{
- if ((info & ~XLR_INFO_MASK) == XLOG_TEST_CUSTOM_RMGRS_MESSAGE)
+ if (info == XLOG_TEST_CUSTOM_RMGRS_MESSAGE)
return "TEST_CUSTOM_RMGRS_MESSAGE";
return NULL;
--
2.51.0
On 14/10/2025 11:13, John Naylor wrote:
Okay, v2 gets rid of the general info mask (split out into 0002 for
readability) and leaves alone the RMGR-specific masks (i.e. leaves out
v1 0002/3). It runs fine with installcheck while streaming to a
standby with wal_consistency_checking. I've also left out the removal
of HEAP2 for now. Giving existing RMGRs more breathing room seems like
a better motivator, going by Nathan's comment and yours.It's worth thinking about backward compatibility if we did go as far
as a 2-byte xl_info (upthread: to allow more RMGR-specific flags, so
e.g. XACT wouldn't need xl_xact_info) In that case, we'd probably
still want a convention that only the lowest byte can contain the
record type. XLogStats could simply assume that in most cases. For
XACT 8 flags in the upper byte still won't be enough, and it will
still need to have its own opcode mask, but that's no worse than the
situation we have already.
First let me say that I'm not objecting to this patch. It makes the code
a little bit more clear, which is good, so I think I'm +0.5 on this
overall. With that said:
I'm not sure I agree with the premise that we should try to get rid of
RM_HEAP2_ID. There's nothing wrong with that scheme as such. As an
alternative, we could easily teach e.g pg_waldump to treat RM_HEAP_ID
and RM_HEAP2_ID the same for statistics purposes.
This patch consumes one of the padding bytes. That's not entirely free,
as there is an opportunity cost: we could squeeze out the padding bytes
and save 2 bytes on every WAL record instead.
typedef struct XLogRecord
{
uint32 xl_tot_len; /* total len of entire record */
TransactionId xl_xid; /* xact id */
XLogRecPtr xl_prev; /* ptr to previous record in log */
uint8 xl_info; /* RMGR-specific info */
RmgrId xl_rmid; /* resource manager for this record */
uint8 xl_geninfo; /* flag bits, see below */
/* 1 byte of padding here, initialize to zero */
pg_crc32c xl_crc; /* CRC for this record *//* XLogRecordBlockHeaders and XLogRecordDataHeader follow, no padding */
} XLogRecord;
I'd suggest some minor reordering and renaming:
typedef struct XLogRecord
{
uint32 xl_tot_len; /* total len of entire record */
TransactionId xl_xid; /* xact id */
XLogRecPtr xl_prev; /* ptr to previous record in log */
uint8 xl_flags; /* flag bits, see below */
RmgrId xl_rmid; /* resource manager for this record */
uint8 xl_rminfo; /* RMGR-specific info */
/* 1 byte of padding here, initialize to zero */
pg_crc32c xl_crc; /* CRC for this record */
/* XLogRecordBlockHeaders and XLogRecordDataHeader follow, no
padding */
} XLogRecord;
In summary:
- Rename 'xl_info' to 'xl_rminfo' to make it more clear that it's
RMGR-specific.
- Rename 'xl_geninfo' to 'xl_flags'. I guess the 'gen' meant 'generic'
or 'general' to distinguish from the rmgr-specific field. But we don't
use a 'gen' prefix like that for any of the other non-rmgr-specific
fields. We could keep it under the old 'xl_info' name instead, but it's
nice to rename it to avoid confusion with the old xl_info field. It now
only contains flags, so 'xl_flags' seems appropriate.
- Reorder the fields so that 'xl_rmid' comes before 'xl_rminfo'. I find
that more intuitive, because the contents of 'xl_rminfo' depends on
'xl_rmid'.
While we're at it, I wonder if it would be more clear to have explicit
'xl_padding' field for the unused byte.
- Heikki
On Tue, Oct 14, 2025 at 03:20:16PM +0300, Heikki Linnakangas wrote:
I'm not sure I agree with the premise that we should try to get rid of
RM_HEAP2_ID. There's nothing wrong with that scheme as such. As an
alternative, we could easily teach e.g pg_waldump to treat RM_HEAP_ID and
RM_HEAP2_ID the same for statistics purposes.
Yeah, I'd rather keep heap2 as well. As long as there is more room
for the record IDs, we're still going to need it in the long run.
This patch consumes one of the padding bytes. That's not entirely free, as
there is an opportunity cost: we could squeeze out the padding bytes and
save 2 bytes on every WAL record instead.
Do you recall an alternative where it would have been possible to save
2 bytes for each record by removing the padding, and still have the
full byte of xl_info be usable freely by each RMGR? I cannot recall
any magic based on how XLogRecord is designed now, but perhaps I
have missed an argument.
We could move out xl_xid, which should not be required for all
records, shaving 4 bytes from the base XLogRecord. I'm afraid of the
duplication this would create if we push this data to each RMGR, which
would, I guess, require a new RMGR callback to retrieve this field on
a per-record basis. But perhaps it would not be that bad.
In summary:
- Rename 'xl_info' to 'xl_rminfo' to make it more clear that it's
RMGR-specific.- Rename 'xl_geninfo' to 'xl_flags'. I guess the 'gen' meant 'generic' or
'general' to distinguish from the rmgr-specific field. But we don't use a
'gen' prefix like that for any of the other non-rmgr-specific fields. We
could keep it under the old 'xl_info' name instead, but it's nice to rename
it to avoid confusion with the old xl_info field. It now only contains
flags, so 'xl_flags' seems appropriate.- Reorder the fields so that 'xl_rmid' comes before 'xl_rminfo'. I find that
more intuitive, because the contents of 'xl_rminfo' depends on 'xl_rmid'.
Okay.
While we're at it, I wonder if it would be more clear to have explicit
'xl_padding' field for the unused byte.
Adding an extra field to document the padding sounds like a good idea
here. It should always be zero, so perhaps it could even be used as a
sanity check?
--
Michael
On Tue, Oct 14, 2025 at 7:20 PM Heikki Linnakangas <hlinnaka@iki.fi> wrote:
This patch consumes one of the padding bytes. That's not entirely free,
as there is an opportunity cost: we could squeeze out the padding bytes
and save 2 bytes on every WAL record instead.
I must be misunderstanding, because I'm not sure how that would work
with the alignment requirement of later parts.
If you mean put some other parts of certain records into header (like
the xl_xact_info idea mentioned earlier, or something else), it's
worth thinking about that -- maybe some things would be helped by this
patch, and others would be closed off by it.
I'd suggest some minor reordering and renaming:
typedef struct XLogRecord
{
uint32 xl_tot_len; /* total len of entire record */
TransactionId xl_xid; /* xact id */
XLogRecPtr xl_prev; /* ptr to previous record in log */
uint8 xl_flags; /* flag bits, see below */
RmgrId xl_rmid; /* resource manager for this record */
uint8 xl_rminfo; /* RMGR-specific info */
/* 1 byte of padding here, initialize to zero */
pg_crc32c xl_crc; /* CRC for this record */
Works for me.
- Rename 'xl_info' to 'xl_rminfo' to make it more clear that it's
RMGR-specific.
That makes sense here in the definition. There are also lots of local
variables named "info", and it would be less invasive to keep those as
they are. Likewise for the macro XLogRecGetInfo.
--
John Naylor
Amazon Web Services
On Wed, Oct 15, 2025 at 6:55 AM Michael Paquier <michael@paquier.xyz> wrote:
On Tue, Oct 14, 2025 at 03:20:16PM +0300, Heikki Linnakangas wrote:
I'm not sure I agree with the premise that we should try to get rid of
RM_HEAP2_ID. There's nothing wrong with that scheme as such. As an
alternative, we could easily teach e.g pg_waldump to treat RM_HEAP_ID and
RM_HEAP2_ID the same for statistics purposes.Yeah, I'd rather keep heap2 as well. As long as there is more room
for the record IDs, we're still going to need it in the long run.
Okay, I'll drop that aspect.
We could move out xl_xid, which should not be required for all
records, shaving 4 bytes from the base XLogRecord. I'm afraid of the
duplication this would create if we push this data to each RMGR, which
would, I guess, require a new RMGR callback to retrieve this field on
a per-record basis. But perhaps it would not be that bad.
I've wondered if it would be possible to make xl_tot_len a varint that
starts in the last byte of the header, with the next bytes being like
XLogRecordDataHeader[Short|Long], but likewise using a varint.
--
John Naylor
Amazon Web Services
On Wed, Oct 15, 2025 at 12:01:44PM +0700, John Naylor wrote:
On Wed, Oct 15, 2025 at 6:55 AM Michael Paquier <michael@paquier.xyz> wrote:
We could move out xl_xid, which should not be required for all
records, shaving 4 bytes from the base XLogRecord. I'm afraid of the
duplication this would create if we push this data to each RMGR, which
would, I guess, require a new RMGR callback to retrieve this field on
a per-record basis. But perhaps it would not be that bad.I've wondered if it would be possible to make xl_tot_len a varint that
starts in the last byte of the header, with the next bytes being like
XLogRecordDataHeader[Short|Long], but likewise using a varint.
This suggestion gives me some shivers, TBH. We've had a couple of
issues with the read of records that spawn across multiple pages,
relying now very strongly on xl_tot_len being the first field in
XLogRecord. Making this field variable may be really tricky while the
code we have now in xlogreader.h is pretty stable.
--
Michael
On 15/10/2025 02:54, Michael Paquier wrote:
On Tue, Oct 14, 2025 at 03:20:16PM +0300, Heikki Linnakangas wrote:
I'm not sure I agree with the premise that we should try to get rid of
RM_HEAP2_ID. There's nothing wrong with that scheme as such. As an
alternative, we could easily teach e.g pg_waldump to treat RM_HEAP_ID and
RM_HEAP2_ID the same for statistics purposes.Yeah, I'd rather keep heap2 as well. As long as there is more room
for the record IDs, we're still going to need it in the long run.
IMO if we do expand xl_info so that we have a full byte for
RMGR-specific info, then it does make sense to get rid of RM_HEAP2_ID
like this patch does. But if that was the only reason for changing the
WAL record header format, I don't think it's worth it.
This patch consumes one of the padding bytes. That's not entirely free, as
there is an opportunity cost: we could squeeze out the padding bytes and
save 2 bytes on every WAL record instead.Do you recall an alternative where it would have been possible to save
2 bytes for each record by removing the padding, and still have the
full byte of xl_info be usable freely by each RMGR? I cannot recall
any magic based on how XLogRecord is designed now, but perhaps I
have missed an argument.
I don't know how to do that. My point was that if we *don't* consume a
full byte for RMGR-specific info, we could remove the two padding bytes
instead and make every WAL record 2 bytes smaller.
- Heikki
On 15/10/2025 07:51, John Naylor wrote:
On Tue, Oct 14, 2025 at 7:20 PM Heikki Linnakangas <hlinnaka@iki.fi> wrote:
This patch consumes one of the padding bytes. That's not entirely free,
as there is an opportunity cost: we could squeeze out the padding bytes
and save 2 bytes on every WAL record instead.I must be misunderstanding, because I'm not sure how that would work
with the alignment requirement of later parts.
We could store xl_crc unaligned. IIRC all the structs that follow that
are already stored unaligned.
- Heikki
On Wed, Oct 15, 2025 at 05:39:38PM +0300, Heikki Linnakangas wrote:
We could store xl_crc unaligned. IIRC all the structs that follow that are
already stored unaligned.
If we do just that, would there be any downside in moving xl_crc to be
just after xl_prev? That would keep the record assembling part
simpler, because XLogRecord is treated as a single object, where the
code relies on a MAXALIGN64() to make sure that the header is aligned.
--
Michael
On 20/10/2025 04:36, Michael Paquier wrote:
On Wed, Oct 15, 2025 at 05:39:38PM +0300, Heikki Linnakangas wrote:
We could store xl_crc unaligned. IIRC all the structs that follow that are
already stored unaligned.If we do just that, would there be any downside in moving xl_crc to be
just after xl_prev? That would keep the record assembling part
simpler, because XLogRecord is treated as a single object, where the
code relies on a MAXALIGN64() to make sure that the header is aligned.
The CRC calculation looks like this:
/*
* Now that xl_prev has been filled in, calculate CRC of the record
* header.
*/
rdata_crc = rechdr->xl_crc;
COMP_CRC32C(rdata_crc, rechdr, offsetof(XLogRecord, xl_crc));
FIN_CRC32C(rdata_crc);
rechdr->xl_crc = rdata_crc;
If 'xl_crc' is not the last field, the above needs to be changed to skip
'xl_crc', or fill it with zeros or something. Similarly in the code that
verifies the checksum. But sure, we could do that.
- Heikki