From b8054982cee3e51db593c9e446cceb6788d7ab13 Mon Sep 17 00:00:00 2001
From: Maxim Orlov <orlovmg@gmail.com>
Date: Fri, 29 Dec 2023 14:42:13 +0300
Subject: [PATCH v1 2/2] Switch to FullTransactionId for XLogRecord->xl_xid

As a step towards 64bit xids switch to FullTransactionId for XLogRecord->xl_xid.

Author: Maxim Orlov <orlovmg@gmail.com>
---
 src/backend/access/transam/xlog.c         |  2 +-
 src/backend/access/transam/xloginsert.c   |  2 +-
 src/backend/access/transam/xlogreader.c   | 17 +---------------
 src/backend/access/transam/xlogrecovery.c |  6 +++---
 src/bin/pg_resetwal/pg_resetwal.c         |  2 +-
 src/bin/pg_waldump/pg_waldump.c           |  2 +-
 src/include/access/xlogreader.h           |  2 +-
 src/include/access/xlogrecord.h           |  9 +++++----
 src/test/recovery/t/039_end_of_wal.pl     | 24 +++++++++++++----------
 9 files changed, 28 insertions(+), 38 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 1264849883..c38a39beda 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -4906,7 +4906,7 @@ BootStrapXLOG(void)
 	recptr = ((char *) page + SizeOfXLogLongPHD);
 	record = (XLogRecord *) recptr;
 	record->xl_prev = 0;
-	record->xl_xid = InvalidTransactionId;
+	record->xl_xid = InvalidFullTransactionId;
 	record->xl_tot_len = SizeOfXLogRecord + SizeOfXLogRecordDataHeaderShort + sizeof(checkPoint);
 	record->xl_info = XLOG_CHECKPOINT_SHUTDOWN;
 	record->xl_rmid = RM_XLOG_ID;
diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c
index e4aaa551a0..8c25e43fb7 100644
--- a/src/backend/access/transam/xloginsert.c
+++ b/src/backend/access/transam/xloginsert.c
@@ -924,7 +924,7 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
 	 * once we know where in the WAL the record will be inserted. The CRC does
 	 * not include the record header yet.
 	 */
-	rechdr->xl_xid = GetCurrentTransactionIdIfAny();
+	rechdr->xl_xid = GetCurrentFullTransactionIdIfAny();
 	rechdr->xl_tot_len = (uint32) total_len;
 	rechdr->xl_info = info;
 	rechdr->xl_rmid = rmid;
diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index 6b404b8169..e1251c8638 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -2171,28 +2171,13 @@ RestoreBlockImage(XLogReaderState *record, uint8 block_id, char *page)
 FullTransactionId
 XLogRecGetFullXid(XLogReaderState *record)
 {
-	TransactionId xid,
-				next_xid;
-	uint32		epoch;
-
 	/*
 	 * This function is only safe during replay, because it depends on the
 	 * replay state.  See AdvanceNextFullTransactionIdPastXid() for more.
 	 */
 	Assert(AmStartupProcess() || !IsUnderPostmaster);
 
-	xid = XLogRecGetXid(record);
-	next_xid = XidFromFullTransactionId(TransamVariables->nextXid);
-	epoch = EpochFromFullTransactionId(TransamVariables->nextXid);
-
-	/*
-	 * If xid is numerically greater than next_xid, it has to be from the last
-	 * epoch.
-	 */
-	if (unlikely(xid > next_xid))
-		--epoch;
-
-	return FullTransactionIdFromEpochAndXid(epoch, xid);
+	return record->record->header.xl_xid;
 }
 
 #endif
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index 6f4f81f992..dd3d770c3a 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -1875,7 +1875,7 @@ ApplyWalRecord(XLogReaderState *xlogreader, XLogRecord *record, TimeLineID *repl
 	/*
 	 * TransamVariables->nextXid must be beyond record's xid.
 	 */
-	AdvanceNextFullTransactionIdPastXid(record->xl_xid);
+	AdvanceNextFullTransactionIdPastXid(XidFromFullTransactionId(record->xl_xid));
 
 	/*
 	 * Before replaying this record, check if this record causes the current
@@ -1933,8 +1933,8 @@ ApplyWalRecord(XLogReaderState *xlogreader, XLogRecord *record, TimeLineID *repl
 	 * If we are attempting to enter Hot Standby mode, process XIDs we see
 	 */
 	if (standbyState >= STANDBY_INITIALIZED &&
-		TransactionIdIsValid(record->xl_xid))
-		RecordKnownAssignedTransactionIds(record->xl_xid);
+		FullTransactionIdIsValid(record->xl_xid))
+		RecordKnownAssignedTransactionIds(XidFromFullTransactionId(record->xl_xid));
 
 	/*
 	 * Some XLOG record types that are related to recovery are processed
diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c
index 5407f51a4e..43eb22d415 100644
--- a/src/bin/pg_resetwal/pg_resetwal.c
+++ b/src/bin/pg_resetwal/pg_resetwal.c
@@ -1105,7 +1105,7 @@ WriteEmptyXLOG(void)
 	recptr = (char *) page + SizeOfXLogLongPHD;
 	record = (XLogRecord *) recptr;
 	record->xl_prev = 0;
-	record->xl_xid = InvalidTransactionId;
+	record->xl_xid = InvalidFullTransactionId;
 	record->xl_tot_len = SizeOfXLogRecord + SizeOfXLogRecordDataHeaderShort + sizeof(CheckPoint);
 	record->xl_info = XLOG_CHECKPOINT_SHUTDOWN;
 	record->xl_rmid = RM_XLOG_ID;
diff --git a/src/bin/pg_waldump/pg_waldump.c b/src/bin/pg_waldump/pg_waldump.c
index a3535bdfa9..7200166282 100644
--- a/src/bin/pg_waldump/pg_waldump.c
+++ b/src/bin/pg_waldump/pg_waldump.c
@@ -1261,7 +1261,7 @@ main(int argc, char **argv)
 			continue;
 
 		if (config.filter_by_xid_enabled &&
-			config.filter_by_xid != record->xl_xid)
+			config.filter_by_xid != XidFromFullTransactionId(record->xl_xid))
 			continue;
 
 		/* check for extended filtering */
diff --git a/src/include/access/xlogreader.h b/src/include/access/xlogreader.h
index 0813722715..0de1cffd4f 100644
--- a/src/include/access/xlogreader.h
+++ b/src/include/access/xlogreader.h
@@ -409,7 +409,7 @@ extern bool DecodeXLogRecord(XLogReaderState *state,
 #define XLogRecGetPrev(decoder) ((decoder)->record->header.xl_prev)
 #define XLogRecGetInfo(decoder) ((decoder)->record->header.xl_info)
 #define XLogRecGetRmid(decoder) ((decoder)->record->header.xl_rmid)
-#define XLogRecGetXid(decoder) ((decoder)->record->header.xl_xid)
+#define XLogRecGetXid(decoder) ((uint32) ((decoder)->record->header.xl_xid.value))
 #define XLogRecGetOrigin(decoder) ((decoder)->record->record_origin)
 #define XLogRecGetTopXid(decoder) ((decoder)->record->toplevel_xid)
 #define XLogRecGetData(decoder) ((decoder)->record->main_data)
diff --git a/src/include/access/xlogrecord.h b/src/include/access/xlogrecord.h
index ec9a3c802a..99157af92a 100644
--- a/src/include/access/xlogrecord.h
+++ b/src/include/access/xlogrecord.h
@@ -12,6 +12,7 @@
 #define XLOGRECORD_H
 
 #include "access/rmgr.h"
+#include "access/transam.h"
 #include "access/xlogdefs.h"
 #include "port/pg_crc32c.h"
 #include "storage/block.h"
@@ -41,18 +42,18 @@
 typedef struct XLogRecord
 {
 	uint32		xl_tot_len;		/* total len of entire record */
-	TransactionId xl_xid;		/* xact id */
+	pg_crc32c	xl_crc;			/* CRC for this record */
+	FullTransactionId xl_xid;	/* xact id */
 	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 */
-	pg_crc32c	xl_crc;			/* CRC for this record */
+	/* 6 bytes of padding here, initialize to zero */
 
 	/* XLogRecordBlockHeaders and XLogRecordDataHeader follow, no padding */
 
 } XLogRecord;
 
-#define SizeOfXLogRecord	(offsetof(XLogRecord, xl_crc) + sizeof(pg_crc32c))
+#define SizeOfXLogRecord	(offsetof(XLogRecord, xl_rmid) + sizeof(RmgrId))
 
 /*
  * The high 4 bits in xl_info may be used freely by rmgr. The
diff --git a/src/test/recovery/t/039_end_of_wal.pl b/src/test/recovery/t/039_end_of_wal.pl
index d2bf062bb2..d4aca99995 100644
--- a/src/test/recovery/t/039_end_of_wal.pl
+++ b/src/test/recovery/t/039_end_of_wal.pl
@@ -21,7 +21,7 @@ use integer;    # causes / operator to use integer math
 my $BIG_ENDIAN = pack("L", 0x12345678) eq pack("N", 0x12345678);
 
 # Header size of record header.
-my $RECORD_HEADER_SIZE = 24;
+my $RECORD_HEADER_SIZE = 26;
 
 # Fields retrieved from code headers.
 my @scan_result = scan_server_header('access/xlog_internal.h',
@@ -131,17 +131,21 @@ sub build_record_header
 
 	# This needs to follow the structure XLogRecord:
 	# I for xl_tot_len
-	# I for xl_xid
+	# I for xl_crc
+	# II for xl_xid
 	# II for xl_prev
 	# C for xl_info
 	# C for xl_rmid
-	# BB for two bytes of padding
-	# I for xl_crc
-	return pack("IIIICCBBI",
-		$xl_tot_len, $xl_xid,
+	# BBBBBB for two bytes of padding
+	return pack("IIIIIICCBBBBBB",
+		$xl_tot_len,
+		$xl_crc,
+		$BIG_ENDIAN ? 0        : $xl_xid,
+		$BIG_ENDIAN ? $xl_xid  : 0,
 		$BIG_ENDIAN ? 0        : $xl_prev,
 		$BIG_ENDIAN ? $xl_prev : 0,
-		$xl_info, $xl_rmid, 0, 0, $xl_crc);
+		$xl_info, $xl_rmid,
+		0, 0, 0, 0, 0, 0);
 }
 
 # Build a fake WAL page header, based on the data given by the caller
@@ -265,7 +269,7 @@ $node->stop('immediate');
 my $log_size = -s $node->logfile;
 $node->start;
 ok( $node->log_contains(
-		"invalid record length at .*: expected at least 24, got 0", $log_size
+		"invalid record length at .*: expected at least 26, got 0", $log_size
 	),
 	"xl_tot_len zero");
 
@@ -277,7 +281,7 @@ write_wal($node, $TLI, $end_lsn, build_record_header(23));
 $log_size = -s $node->logfile;
 $node->start;
 ok( $node->log_contains(
-		"invalid record length at .*: expected at least 24, got 23",
+		"invalid record length at .*: expected at least 26, got 23",
 		$log_size),
 	"xl_tot_len short");
 
@@ -290,7 +294,7 @@ write_wal($node, $TLI, $end_lsn, build_record_header(1));
 $log_size = -s $node->logfile;
 $node->start;
 ok( $node->log_contains(
-		"invalid record length at .*: expected at least 24, got 1", $log_size
+		"invalid record length at .*: expected at least 26, got 1", $log_size
 	),
 	"xl_tot_len short at end-of-page");
 
-- 
2.42.0

