From 3ca3cd6a7178e7f8d81d7205f362ac67911fc2bb Mon Sep 17 00:00:00 2001
From: Matthias van de Meent <boekewurm+postgres@gmail.com>
Date: Mon, 23 Jan 2023 17:21:12 +0100
Subject: [PATCH v5 4/7] Move rmgr info bits into their own field in the xlog
 record header.

This takes one byte of the 2 previously lost to alignment, and allows
each rmgr to use more info bits (useful for e.g. merging the heap rmgrs
back into one).
---
 contrib/pg_walinspect/pg_walinspect.c       |  7 +++---
 src/backend/access/transam/xact.c           | 22 +++++++++--------
 src/backend/access/transam/xlog.c           |  7 +++---
 src/backend/access/transam/xloginsert.c     | 27 ++++++++++++---------
 src/backend/access/transam/xlogprefetcher.c |  2 +-
 src/backend/access/transam/xlogreader.c     |  2 +-
 src/backend/access/transam/xlogrecovery.c   | 10 ++++----
 src/backend/access/transam/xlogstats.c      | 12 ++++-----
 src/backend/catalog/storage.c               |  7 +++---
 src/backend/commands/dbcommands.c           | 20 +++++++++------
 src/backend/utils/probes.d                  |  2 +-
 src/bin/pg_resetwal/pg_resetwal.c           |  3 ++-
 src/bin/pg_rewind/parsexlog.c               |  4 +--
 src/bin/pg_waldump/pg_waldump.c             |  7 +++---
 src/include/access/brin_xlog.h              |  3 +--
 src/include/access/heapam_xlog.h            |  4 +--
 src/include/access/nbtxlog.h                |  3 +--
 src/include/access/xact.h                   |  6 ++---
 src/include/access/xlog_internal.h          |  2 +-
 src/include/access/xloginsert.h             |  3 ++-
 src/include/access/xlogreader.h             |  4 +--
 src/include/access/xlogrecord.h             | 11 ++-------
 src/include/access/xlogstats.h              |  5 ++--
 23 files changed, 89 insertions(+), 84 deletions(-)

diff --git a/contrib/pg_walinspect/pg_walinspect.c b/contrib/pg_walinspect/pg_walinspect.c
index 1b6f4cb178..909700f9a1 100644
--- a/contrib/pg_walinspect/pg_walinspect.c
+++ b/contrib/pg_walinspect/pg_walinspect.c
@@ -697,7 +697,7 @@ GetXLogSummaryStats(XLogStats *stats, ReturnSetInfo *rsinfo,
 		{
 			int			rj;
 
-			for (rj = 0; rj < MAX_XLINFO_TYPES; rj++)
+			for (rj = 0; rj < MAX_XLRMGRINFO_TYPES; rj++)
 			{
 				const char *id;
 
@@ -712,10 +712,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 c560f07390..da0ac6c8d3 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -5650,7 +5650,8 @@ XactLogCommitRecord(TimestampTz commit_time,
 	xl_xact_invals xl_invals;
 	xl_xact_twophase xl_twophase;
 	xl_xact_origin xl_origin;
-	uint8		info;
+	uint8		info = 0;
+	uint8		rmgr_info;
 
 	Assert(CritSectionCount > 0);
 
@@ -5658,9 +5659,9 @@ XactLogCommitRecord(TimestampTz commit_time,
 
 	/* decide between a plain and 2pc commit */
 	if (!TransactionIdIsValid(twophase_xid))
-		info = XLOG_XACT_COMMIT;
+		rmgr_info = XLOG_XACT_COMMIT;
 	else
-		info = XLOG_XACT_COMMIT_PREPARED;
+		rmgr_info = XLOG_XACT_COMMIT_PREPARED;
 
 	/* First figure out and collect all the information needed */
 
@@ -5736,7 +5737,7 @@ XactLogCommitRecord(TimestampTz commit_time,
 	}
 
 	if (xl_xinfo.xinfo != 0)
-		info |= XLOG_XACT_HAS_INFO;
+		rmgr_info |= XLOG_XACT_HAS_INFO;
 
 	/* Then include all the collected data into the commit record. */
 
@@ -5794,7 +5795,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, rmgr_info);
 }
 
 /*
@@ -5820,7 +5821,8 @@ XactLogAbortRecord(TimestampTz abort_time,
 	xl_xact_dbinfo xl_dbinfo;
 	xl_xact_origin xl_origin;
 
-	uint8		info;
+	uint8		info = 0;
+	uint8		rmgr_info;
 
 	Assert(CritSectionCount > 0);
 
@@ -5828,9 +5830,9 @@ XactLogAbortRecord(TimestampTz abort_time,
 
 	/* decide between a plain and 2pc abort */
 	if (!TransactionIdIsValid(twophase_xid))
-		info = XLOG_XACT_ABORT;
+		rmgr_info = XLOG_XACT_ABORT;
 	else
-		info = XLOG_XACT_ABORT_PREPARED;
+		rmgr_info = XLOG_XACT_ABORT_PREPARED;
 
 
 	/* First figure out and collect all the information needed */
@@ -5889,7 +5891,7 @@ XactLogAbortRecord(TimestampTz abort_time,
 	}
 
 	if (xl_xinfo.xinfo != 0)
-		info |= XLOG_XACT_HAS_INFO;
+		rmgr_info |= XLOG_XACT_HAS_INFO;
 
 	/* Then include all the collected data into the abort record. */
 
@@ -5940,7 +5942,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, rmgr_info);
 }
 
 /*
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 08c78bf57b..eded22ab1d 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -738,9 +738,9 @@ XLogInsertRecord(XLogRecData *rdata,
 	pg_crc32c	rdata_crc;
 	bool		inserted;
 	XLogRecord *rechdr = (XLogRecord *) rdata->data;
-	uint8		info = rechdr->xl_info & ~XLR_INFO_MASK;
+	uint8		rmgrinfo = rechdr->xl_rmgrinfo;
 	bool		isLogSwitch = (rechdr->xl_rmid == RM_XLOG_ID &&
-							   info == XLOG_SWITCH);
+							   rmgrinfo == XLOG_SWITCH);
 	XLogRecPtr	StartPos;
 	XLogRecPtr	EndPos;
 	bool		prevDoPageWrites = doPageWrites;
@@ -4753,7 +4753,8 @@ BootStrapXLOG(void)
 	record->xl_prev = 0;
 	record->xl_xid = InvalidTransactionId;
 	record->xl_tot_len = SizeOfXLogRecord + SizeOfXLogRecordDataHeaderShort + sizeof(checkPoint);
-	record->xl_info = XLOG_CHECKPOINT_SHUTDOWN;
+	record->xl_info = 0;
+	record->xl_rmgrinfo = XLOG_CHECKPOINT_SHUTDOWN;
 	record->xl_rmid = RM_XLOG_ID;
 	recptr += SizeOfXLogRecord;
 	/* fill the XLogRecordDataHeaderShort struct */
diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c
index 51b487887b..9596a37cb2 100644
--- a/src/backend/access/transam/xloginsert.c
+++ b/src/backend/access/transam/xloginsert.c
@@ -135,7 +135,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 rmgr_info,
 									   XLogRecPtr RedoRecPtr, bool doPageWrites,
 									   XLogRecPtr *fpw_lsn, int *num_fpi,
 									   bool *topxid_included);
@@ -447,9 +447,9 @@ XLogSetRecordFlags(uint8 flags)
 }
 
 /*
- * Insert an XLOG record having the specified RMID and info bytes, with the
- * body of the record being the data and buffer references registered earlier
- * with XLogRegister* calls.
+ * Insert an XLOG record having the specified RMID and rmgr_info bytes, with
+ * the body of the record being the data and buffer references registered
+ * earlier with XLogRegister* calls.
  *
  * Returns XLOG pointer to end of record (beginning of next record).
  * This can be used as LSN for data pages affected by the logged action.
@@ -458,7 +458,13 @@ XLogSetRecordFlags(uint8 flags)
  * WAL rule "write the log before the data".)
  */
 XLogRecPtr
-XLogInsert(RmgrId rmid, uint8 info)
+XLogInsert(RmgrId rmid, uint8 rmgr_info)
+{
+	return XLogInsertExtended(rmid, 0, rmgr_info);
+}
+
+XLogRecPtr
+XLogInsertExtended(RmgrId rmid, uint8 info, uint8 rmgr_info)
 {
 	XLogRecPtr	EndPos;
 
@@ -470,12 +476,11 @@ XLogInsert(RmgrId rmid, uint8 info)
 	 * The caller can set rmgr bits, 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 |
+	if ((info & ~(XLR_SPECIAL_REL_UPDATE |
 				  XLR_CHECK_CONSISTENCY)) != 0)
 		elog(PANIC, "invalid xlog info mask %02X", info);
 
-	TRACE_POSTGRESQL_WAL_INSERT(rmid, info);
+	TRACE_POSTGRESQL_WAL_INSERT(rmid, info, rmgr_info);
 
 	/*
 	 * In bootstrap mode, we don't actually log anything but XLOG resources;
@@ -504,7 +509,7 @@ XLogInsert(RmgrId rmid, uint8 info)
 		 */
 		GetFullPageWriteInfo(&RedoRecPtr, &doPageWrites);
 
-		rdt = XLogRecordAssemble(rmid, info, RedoRecPtr, doPageWrites,
+		rdt = XLogRecordAssemble(rmid, info, rmgr_info, RedoRecPtr, doPageWrites,
 								 &fpw_lsn, &num_fpi, &topxid_included);
 
 		EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags, num_fpi,
@@ -532,8 +537,7 @@ XLogInsert(RmgrId rmid, uint8 info)
  * current subtransaction.
  */
 static XLogRecData *
-XLogRecordAssemble(RmgrId rmid, uint8 info,
-				   XLogRecPtr RedoRecPtr, bool doPageWrites,
+XLogRecordAssemble(RmgrId rmid, uint8 info, uint8 rmgr_info, XLogRecPtr RedoRecPtr, bool doPageWrites,
 				   XLogRecPtr *fpw_lsn, int *num_fpi, bool *topxid_included)
 {
 	XLogRecData *rdt;
@@ -924,6 +928,7 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
 	rechdr->xl_tot_len = (uint32) total_len;
 	rechdr->xl_info = info;
 	rechdr->xl_rmid = rmid;
+	rechdr->xl_rmgrinfo = rmgr_info;
 	rechdr->xl_prev = InvalidXLogRecPtr;
 	rechdr->xl_crc = rdata_crc;
 
diff --git a/src/backend/access/transam/xlogprefetcher.c b/src/backend/access/transam/xlogprefetcher.c
index 539928cb85..dd4ca866a4 100644
--- a/src/backend/access/transam/xlogprefetcher.c
+++ b/src/backend/access/transam/xlogprefetcher.c
@@ -536,7 +536,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_rmgrinfo;
 
 			if (rmid == RM_XLOG_ID)
 			{
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index becb207152..bebdf1759a 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -860,7 +860,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_rmgrinfo == 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 6508246999..56fa2f74a2 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -632,7 +632,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_rmgrinfo == XLOG_CHECKPOINT_SHUTDOWN);
 			ereport(DEBUG1,
 					(errmsg_internal("checkpoint record is at %X/%X",
 									 LSN_FORMAT_ARGS(CheckPointLoc))));
@@ -786,7 +786,7 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
 					(errmsg("could not locate a valid checkpoint record")));
 		}
 		memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint));
-		wasShutdown = ((record->xl_info & ~XLR_INFO_MASK) == XLOG_CHECKPOINT_SHUTDOWN);
+		wasShutdown = (record->xl_rmgrinfo == XLOG_CHECKPOINT_SHUTDOWN);
 	}
 
 	/*
@@ -1857,7 +1857,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_rmgrinfo;
 
 		if (info == XLOG_CHECKPOINT_SHUTDOWN)
 		{
@@ -3992,12 +3992,12 @@ 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_rmgrinfo;
 	if (info != XLOG_CHECKPOINT_SHUTDOWN &&
 		info != XLOG_CHECKPOINT_ONLINE)
 	{
 		ereport(LOG,
-				(errmsg("invalid xl_info in checkpoint record")));
+				(errmsg("invalid xl_rmgrinfo in checkpoint record")));
 		return NULL;
 	}
 	if (record->xl_tot_len != SizeOfXLogRecord + SizeOfXLogRecordDataHeaderShort + sizeof(CheckPoint))
diff --git a/src/backend/access/transam/xlogstats.c b/src/backend/access/transam/xlogstats.c
index 267b108943..28d6d971ac 100644
--- a/src/backend/access/transam/xlogstats.c
+++ b/src/backend/access/transam/xlogstats.c
@@ -74,21 +74,21 @@ 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
+	 * combination of the RmgrId and the eight bits of the xl_rmgrinfo field
+	 * that are the rmgr's domain (resulting in 256 possible entries per
 	 * RmgrId).
 	 */
 
-	recid = XLogRecGetRmgrInfo(record) >> 4;
+	recid = XLogRecGetRmgrInfo(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.
+	 * following three bits for the opcode. We filter opcode out of
+	 * xl_rmgrinfo and use it as the identifier of the record.
 	 */
 	if (rmid == RM_XACT_ID)
-		recid &= 0x07;
+		recid &= 0x70;
 
 	stats->record_stats[rmid][recid].count++;
 	stats->record_stats[rmid][recid].rec_len += rec_len;
diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c
index 9ce4d9a920..0048ce81d7 100644
--- a/src/backend/catalog/storage.c
+++ b/src/backend/catalog/storage.c
@@ -194,7 +194,7 @@ log_smgrcreate(const RelFileLocator *rlocator, ForkNumber forkNum)
 
 	XLogBeginInsert();
 	XLogRegisterData((char *) &xlrec, sizeof(xlrec));
-	XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE | XLR_SPECIAL_REL_UPDATE);
+	XLogInsertExtended(RM_SMGR_ID, XLR_SPECIAL_REL_UPDATE, XLOG_SMGR_CREATE);
 }
 
 /*
@@ -375,8 +375,9 @@ RelationTruncate(Relation rel, BlockNumber nblocks)
 		XLogBeginInsert();
 		XLogRegisterData((char *) &xlrec, sizeof(xlrec));
 
-		lsn = XLogInsert(RM_SMGR_ID,
-						 XLOG_SMGR_TRUNCATE | XLR_SPECIAL_REL_UPDATE);
+		lsn = XLogInsertExtended(RM_SMGR_ID,
+								 XLR_SPECIAL_REL_UPDATE,
+								 XLOG_SMGR_TRUNCATE);
 
 		/*
 		 * 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 bc061a697d..1f6d670fa6 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -624,8 +624,9 @@ CreateDatabaseUsingFileCopy(Oid src_dboid, Oid dst_dboid, Oid src_tsid,
 			XLogRegisterData((char *) &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,
+									  XLR_SPECIAL_REL_UPDATE,
+									  XLOG_DBASE_CREATE_FILE_COPY);
 		}
 		pfree(srcpath);
 		pfree(dstpath);
@@ -2112,8 +2113,9 @@ movedb(const char *dbname, const char *tblspcname)
 			XLogRegisterData((char *) &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,
+									  XLR_SPECIAL_REL_UPDATE,
+									  XLOG_DBASE_CREATE_FILE_COPY);
 		}
 
 		/*
@@ -2206,8 +2208,9 @@ movedb(const char *dbname, const char *tblspcname)
 		XLogRegisterData((char *) &xlrec, sizeof(xl_dbase_drop_rec));
 		XLogRegisterData((char *) &src_tblspcoid, sizeof(Oid));
 
-		(void) XLogInsert(RM_DBASE_ID,
-						  XLOG_DBASE_DROP | XLR_SPECIAL_REL_UPDATE);
+		(void) XLogInsertExtended(RM_DBASE_ID,
+								  XLR_SPECIAL_REL_UPDATE,
+								  XLOG_DBASE_DROP);
 	}
 
 	/* Now it's safe to release the database lock */
@@ -2937,8 +2940,9 @@ remove_dbtablespaces(Oid db_id)
 		XLogRegisterData((char *) &xlrec, MinSizeOfDbaseDropRec);
 		XLogRegisterData((char *) tablespace_ids, ntblspc * sizeof(Oid));
 
-		(void) XLogInsert(RM_DBASE_ID,
-						  XLOG_DBASE_DROP | XLR_SPECIAL_REL_UPDATE);
+		(void) XLogInsertExtended(RM_DBASE_ID,
+								  XLR_SPECIAL_REL_UPDATE,
+								  XLOG_DBASE_DROP);
 	}
 
 	list_free(ltblspc);
diff --git a/src/backend/utils/probes.d b/src/backend/utils/probes.d
index 0af275587b..131067b5ac 100644
--- a/src/backend/utils/probes.d
+++ b/src/backend/utils/probes.d
@@ -87,7 +87,7 @@ provider postgresql {
 	probe smgr__md__write__start(ForkNumber, BlockNumber, Oid, Oid, Oid, int);
 	probe smgr__md__write__done(ForkNumber, BlockNumber, Oid, Oid, Oid, int, int, int);
 
-	probe wal__insert(unsigned char, unsigned char);
+	probe wal__insert(unsigned char, unsigned char, unsigned char);
 	probe wal__switch();
 	probe wal__buffer__write__dirty__start();
 	probe wal__buffer__write__dirty__done();
diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c
index 25ecdaaa15..8e61a7117e 100644
--- a/src/bin/pg_resetwal/pg_resetwal.c
+++ b/src/bin/pg_resetwal/pg_resetwal.c
@@ -1070,7 +1070,8 @@ WriteEmptyXLOG(void)
 	record->xl_prev = 0;
 	record->xl_xid = InvalidTransactionId;
 	record->xl_tot_len = SizeOfXLogRecord + SizeOfXLogRecordDataHeaderShort + sizeof(CheckPoint);
-	record->xl_info = XLOG_CHECKPOINT_SHUTDOWN;
+	record->xl_info = 0;
+	record->xl_rmgrinfo = XLOG_CHECKPOINT_SHUTDOWN;
 	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 2b6b46f0e3..aa03fe8031 100644
--- a/src/bin/pg_rewind/parsexlog.c
+++ b/src/bin/pg_rewind/parsexlog.c
@@ -438,9 +438,9 @@ extractPageInfo(XLogReaderState *record)
 		 * track that change.
 		 */
 		pg_fatal("WAL record modifies a relation, but record type is not recognized: "
-				 "lsn: %X/%X, rmid: %d, rmgr: %s, info: %02X",
+				 "lsn: %X/%X, rmid: %d, rmgr: %s, info: %02X, rmgrinfo: %02X",
 				 LSN_FORMAT_ARGS(record->ReadRecPtr),
-				 rmid, RmgrName(rmid), info | rminfo);
+				 rmid, RmgrName(rmid), info, rminfo);
 	}
 
 	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 48b733b767..fb6a5e76b1 100644
--- a/src/bin/pg_waldump/pg_waldump.c
+++ b/src/bin/pg_waldump/pg_waldump.c
@@ -698,7 +698,7 @@ XLogDumpDisplayStats(XLogDumpConfig *config, XLogStats *stats)
 		}
 		else
 		{
-			for (rj = 0; rj < MAX_XLINFO_TYPES; rj++)
+			for (rj = 0; rj < MAX_XLRMGRINFO_TYPES; rj++)
 			{
 				const char *id;
 
@@ -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/brin_xlog.h b/src/include/access/brin_xlog.h
index 45a688d09b..92190688c9 100644
--- a/src/include/access/brin_xlog.h
+++ b/src/include/access/brin_xlog.h
@@ -25,8 +25,7 @@
 /*
  * WAL record definitions for BRIN's WAL operations
  *
- * XLOG allows to store some information in high 4 bits of log
- * record xl_info field.
+ * XLOG allows to store some information in the 8-bit xl_rmgrinfo field.
  */
 #define XLOG_BRIN_CREATE_INDEX		0x00
 #define XLOG_BRIN_INSERT			0x10
diff --git a/src/include/access/heapam_xlog.h b/src/include/access/heapam_xlog.h
index 70e9acd350..6705c8a316 100644
--- a/src/include/access/heapam_xlog.h
+++ b/src/include/access/heapam_xlog.h
@@ -26,8 +26,8 @@
 /*
  * 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 some information in the 8-bit xl_rmgrinfo field.
+ * We use 3 for opcode and one for init bit.
  */
 #define XLOG_HEAP_INSERT		0x00
 #define XLOG_HEAP_DELETE		0x10
diff --git a/src/include/access/nbtxlog.h b/src/include/access/nbtxlog.h
index 422ac13d56..6d1231a01e 100644
--- a/src/include/access/nbtxlog.h
+++ b/src/include/access/nbtxlog.h
@@ -21,8 +21,7 @@
 /*
  * XLOG records for btree operations
  *
- * XLOG allows to store some information in high 4 bits of log
- * record xl_info field
+ * XLOG allows to store some information in the 8-bit xl_rmgrinfo field.
  */
 #define XLOG_BTREE_INSERT_LEAF	0x00	/* add index tuple without split */
 #define XLOG_BTREE_INSERT_UPPER 0x10	/* same, on a non-leaf page */
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index b94b264402..2a9a708279 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -163,8 +163,8 @@ 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 some information in the 8-bit xl_rmgrinfo field.
+ * We use 3 for the opcode, and one about an optional flag variable.
  */
 #define XLOG_XACT_COMMIT			0x00
 #define XLOG_XACT_PREPARE			0x10
@@ -232,7 +232,7 @@ typedef struct xl_xact_assignment
  * A minimal commit/abort record only consists of a xl_xact_commit/abort
  * struct. The presence of additional information is indicated by bits set in
  * 'xl_xact_xinfo->xinfo'. The presence of the xinfo field itself is signaled
- * by a set XLOG_XACT_HAS_INFO bit in the xl_info field.
+ * by a set XLOG_XACT_HAS_INFO bit in the xl_rmgrinfo field.
  *
  * NB: All the individual data chunks should be sized to multiples of
  * sizeof(int) and only require int32 alignment. If they require bigger
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index af822b471b..9413836a6a 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -463,7 +463,7 @@ static inline int XLogReadLength(uint32 *length, XLogSizeClass sizeClass,
  * This struct must be kept in sync with the PG_RMGR definition in
  * rmgr.c.
  *
- * rm_identify must return a name for the record based on xl_info (without
+ * rm_identify must return a name for the record based on xl_rmgrinfo (without
  * reference to the rmid). For example, XLOG_BTREE_VACUUM would be named
  * "VACUUM". rm_desc can then be called to obtain additional detail for the
  * record, if available (e.g. the last block).
diff --git a/src/include/access/xloginsert.h b/src/include/access/xloginsert.h
index 31785dc578..c6c46e5409 100644
--- a/src/include/access/xloginsert.h
+++ b/src/include/access/xloginsert.h
@@ -41,7 +41,8 @@
 /* prototypes for public functions in xloginsert.c: */
 extern void XLogBeginInsert(void);
 extern void XLogSetRecordFlags(uint8 flags);
-extern XLogRecPtr XLogInsert(RmgrId rmid, uint8 info);
+extern XLogRecPtr XLogInsertExtended(RmgrId rmid, uint8 info, uint8 rmgr_info);
+extern XLogRecPtr XLogInsert(RmgrId rmid, uint8 rmgr_info);
 extern void XLogEnsureRecordSpace(int max_block_id, int ndatas);
 extern void XLogRegisterData(char *data, uint32 len);
 extern void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags);
diff --git a/src/include/access/xlogreader.h b/src/include/access/xlogreader.h
index 2b976dcc03..a1d0216404 100644
--- a/src/include/access/xlogreader.h
+++ b/src/include/access/xlogreader.h
@@ -407,8 +407,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 & XLR_INFO_MASK)
-#define XLogRecGetRmgrInfo(decoder) (((decoder)->record->header.xl_info) & XLR_RMGR_INFO_MASK)
+#define XLogRecGetInfo(decoder) ((decoder)->record->header.xl_info)
+#define XLogRecGetRmgrInfo(decoder) ((decoder)->record->header.xl_rmgrinfo)
 #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 c1c4f04a06..0f32f20591 100644
--- a/src/include/access/xlogrecord.h
+++ b/src/include/access/xlogrecord.h
@@ -67,7 +67,8 @@ 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 */
+	uint8		xl_rmgrinfo;	/* rmgr 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 */
@@ -76,14 +77,6 @@ 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
  * chunk.  This means that a single XLogRecord cannot exceed MaxAllocSize
diff --git a/src/include/access/xlogstats.h b/src/include/access/xlogstats.h
index 89410ce92b..30974f5ba7 100644
--- a/src/include/access/xlogstats.h
+++ b/src/include/access/xlogstats.h
@@ -16,7 +16,8 @@
 #include "access/rmgr.h"
 #include "access/xlogreader.h"
 
-#define MAX_XLINFO_TYPES 16
+/* all 8 bits of xl_rmgrinfo are available */
+#define MAX_XLRMGRINFO_TYPES 256
 
 typedef struct XLogRecStats
 {
@@ -33,7 +34,7 @@ typedef struct XLogStats
 	XLogRecPtr	endptr;
 #endif
 	XLogRecStats rmgr_stats[RM_MAX_ID + 1];
-	XLogRecStats record_stats[RM_MAX_ID + 1][MAX_XLINFO_TYPES];
+	XLogRecStats record_stats[RM_MAX_ID + 1][MAX_XLRMGRINFO_TYPES];
 } XLogStats;
 
 extern void XLogRecGetLen(XLogReaderState *record, uint32 *rec_len,
-- 
2.40.1

