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.
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. 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] https://www.postgresql.org/message-id/20220715173731.6t3km5cww3f5ztfq%40awork3.anarazel.de [2] https://www.postgresql.org/message-id/CA%2BTgmoa7pNxxe_K%3D3mTHHZGSmnrc_YgApArx3OFHN2g57nzLNw%40mail.gmail.com [3] https://www.postgresql.org/message-id/CAEze2Wjd3jY_UhhOGdGGnC6NO%3D%2BNmtNOmd%3DJaYv-v-nwBAiXXA%40mail.gmail.com -- John Naylor Amazon Web Services
From 08edc80158627bd23018d437e31ee47e2fbd0553 Mon Sep 17 00:00:00 2001 From: John Naylor <[email protected]> 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
From 7b24fd5139507a80d0edba994abe0a80ae1ac243 Mon Sep 17 00:00:00 2001 From: John Naylor <[email protected]> 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
From 448fabb2edefd714fad7f03cf0c445d53b74835e Mon Sep 17 00:00:00 2001 From: John Naylor <[email protected]> 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
From 4c76d0a3a6242eae605f605f7ba229581832c0d1 Mon Sep 17 00:00:00 2001 From: John Naylor <[email protected]> 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
