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

