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

