From 0ec22e855f95c9817bb56c795188c5dfdd957b4c Mon Sep 17 00:00:00 2001
From: Vigneshwaran c <vignesh21@gmail.com>
Date: Thu, 1 Aug 2019 11:25:39 +0530
Subject: [PATCH 1/3] Use FullTransactionId for two phase commit.

Store full transaction IDs in the files and data structures used
for two phase commit.  For now subtransactions are still stored in
32 bit format.

Author: Vignesh C
Discussion: https://postgr.es/m/CALDaNm2fFeQC_SbM_LsSPNZG3HZ0SC34szY+451iW7oysAb8Cw@mail.gmail.com
---
 src/backend/access/transam/twophase.c | 50 +++++++++++++--------------
 src/backend/access/transam/xact.c     |  4 +--
 src/include/access/transam.h          |  1 +
 src/include/access/twophase.h         |  3 +-
 4 files changed, 30 insertions(+), 28 deletions(-)

diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 477709bbc2..89e98be7b4 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -163,7 +163,7 @@ typedef struct GlobalTransactionData
 	 */
 	XLogRecPtr	prepare_start_lsn;	/* XLOG offset of prepare record start */
 	XLogRecPtr	prepare_end_lsn;	/* XLOG offset of prepare record end */
-	TransactionId xid;			/* The GXACT id */
+	FullTransactionId full_xid; /* The GXACT full xid */
 
 	Oid			owner;			/* ID of user that executed the xact */
 	BackendId	locking_backend;	/* backend currently working on the xact */
@@ -224,7 +224,7 @@ static void XlogReadTwoPhaseData(XLogRecPtr lsn, char **buf, int *len);
 static char *ProcessTwoPhaseBuffer(TransactionId xid,
 								   XLogRecPtr prepare_start_lsn,
 								   bool fromdisk, bool setParent, bool setNextXid);
-static void MarkAsPreparingGuts(GlobalTransaction gxact, TransactionId xid,
+static void MarkAsPreparingGuts(GlobalTransaction gxact, FullTransactionId full_xid,
 								const char *gid, TimestampTz prepared_at, Oid owner,
 								Oid databaseid);
 static void RemoveTwoPhaseFile(TransactionId xid, bool giveWarning);
@@ -370,7 +370,7 @@ PostPrepare_Twophase(void)
  *		Reserve the GID for the given transaction.
  */
 GlobalTransaction
-MarkAsPreparing(TransactionId xid, const char *gid,
+MarkAsPreparing(FullTransactionId full_xid, const char *gid,
 				TimestampTz prepared_at, Oid owner, Oid databaseid)
 {
 	GlobalTransaction gxact;
@@ -421,7 +421,7 @@ MarkAsPreparing(TransactionId xid, const char *gid,
 	gxact = TwoPhaseState->freeGXacts;
 	TwoPhaseState->freeGXacts = gxact->next;
 
-	MarkAsPreparingGuts(gxact, xid, gid, prepared_at, owner, databaseid);
+	MarkAsPreparingGuts(gxact, full_xid, gid, prepared_at, owner, databaseid);
 
 	gxact->ondisk = false;
 
@@ -444,7 +444,7 @@ MarkAsPreparing(TransactionId xid, const char *gid,
  * Note: This function should be called with appropriate locks held.
  */
 static void
-MarkAsPreparingGuts(GlobalTransaction gxact, TransactionId xid, const char *gid,
+MarkAsPreparingGuts(GlobalTransaction gxact, FullTransactionId full_xid, const char *gid,
 					TimestampTz prepared_at, Oid owner, Oid databaseid)
 {
 	PGPROC	   *proc;
@@ -463,8 +463,8 @@ MarkAsPreparingGuts(GlobalTransaction gxact, TransactionId xid, const char *gid,
 	SHMQueueElemInit(&(proc->links));
 	proc->waitStatus = STATUS_OK;
 	/* We set up the gxact's VXID as InvalidBackendId/XID */
-	proc->lxid = (LocalTransactionId) xid;
-	pgxact->xid = xid;
+	proc->lxid = (LocalTransactionId) XidFromFullTransactionId(full_xid);
+	pgxact->xid = XidFromFullTransactionId(full_xid);
 	pgxact->xmin = InvalidTransactionId;
 	pgxact->delayChkpt = false;
 	pgxact->vacuumFlags = 0;
@@ -485,7 +485,7 @@ MarkAsPreparingGuts(GlobalTransaction gxact, TransactionId xid, const char *gid,
 	pgxact->nxids = 0;
 
 	gxact->prepared_at = prepared_at;
-	gxact->xid = xid;
+	gxact->full_xid = full_xid;
 	gxact->owner = owner;
 	gxact->locking_backend = MyBackendId;
 	gxact->valid = false;
@@ -915,7 +915,7 @@ typedef struct TwoPhaseFileHeader
 {
 	uint32		magic;			/* format identifier */
 	uint32		total_len;		/* actual file length */
-	TransactionId xid;			/* original transaction XID */
+	FullTransactionId full_xid; /* original full transaction XID */
 	Oid			database;		/* OID of database it was in */
 	TimestampTz prepared_at;	/* time of preparation */
 	Oid			owner;			/* user running the transaction */
@@ -1004,8 +1004,6 @@ void
 StartPrepare(GlobalTransaction gxact)
 {
 	PGPROC	   *proc = &ProcGlobal->allProcs[gxact->pgprocno];
-	PGXACT	   *pgxact = &ProcGlobal->allPgXact[gxact->pgprocno];
-	TransactionId xid = pgxact->xid;
 	TwoPhaseFileHeader hdr;
 	TransactionId *children;
 	RelFileNode *commitrels;
@@ -1028,7 +1026,7 @@ StartPrepare(GlobalTransaction gxact)
 	/* Create header */
 	hdr.magic = TWOPHASE_MAGIC;
 	hdr.total_len = 0;			/* EndPrepare will fill this in */
-	hdr.xid = xid;
+	hdr.full_xid = gxact->full_xid;
 	hdr.database = proc->databaseId;
 	hdr.prepared_at = gxact->prepared_at;
 	hdr.owner = gxact->owner;
@@ -1346,7 +1344,7 @@ ParsePrepareRecord(uint8 info, char *xlrec, xl_xact_parsed_prepare *parsed)
 
 	parsed->origin_lsn = hdr->origin_lsn;
 	parsed->origin_timestamp = hdr->origin_timestamp;
-	parsed->twophase_xid = hdr->xid;
+	parsed->twophase_xid = XidFromFullTransactionId(hdr->full_xid);
 	parsed->dbId = hdr->database;
 	parsed->nsubxacts = hdr->nsubxacts;
 	parsed->nrels = hdr->ncommitrels;
@@ -1442,7 +1440,7 @@ StandbyTransactionIdIsPrepared(TransactionId xid)
 
 	/* Check header also */
 	hdr = (TwoPhaseFileHeader *) buf;
-	result = TransactionIdEquals(hdr->xid, xid);
+	result = TransactionIdEquals(XidFromFullTransactionId(hdr->full_xid), xid);
 	pfree(buf);
 
 	return result;
@@ -1493,7 +1491,7 @@ FinishPreparedTransaction(const char *gid, bool isCommit)
 	 * Disassemble the header area
 	 */
 	hdr = (TwoPhaseFileHeader *) buf;
-	Assert(TransactionIdEquals(hdr->xid, xid));
+	Assert(TransactionIdEquals(XidFromFullTransactionId(hdr->full_xid), xid));
 	bufptr = buf + MAXALIGN(sizeof(TwoPhaseFileHeader));
 	bufptr += MAXALIGN(hdr->gidlen);
 	children = (TransactionId *) bufptr;
@@ -1791,7 +1789,8 @@ CheckPointTwoPhase(XLogRecPtr redo_horizon)
 			int			len;
 
 			XlogReadTwoPhaseData(gxact->prepare_start_lsn, &buf, &len);
-			RecreateTwoPhaseFile(gxact->xid, buf, len);
+			RecreateTwoPhaseFile(XidFromFullTransactionId(gxact->full_xid),
+								 buf, len);
 			gxact->ondisk = true;
 			gxact->prepare_start_lsn = InvalidXLogRecPtr;
 			gxact->prepare_end_lsn = InvalidXLogRecPtr;
@@ -1911,7 +1910,7 @@ PrescanPreparedTransactions(TransactionId **xids_p, int *nxids_p)
 
 		Assert(gxact->inredo);
 
-		xid = gxact->xid;
+		xid = XidFromFullTransactionId(gxact->full_xid);
 
 		buf = ProcessTwoPhaseBuffer(xid,
 									gxact->prepare_start_lsn,
@@ -1986,7 +1985,7 @@ StandbyRecoverPreparedTransactions(void)
 
 		Assert(gxact->inredo);
 
-		xid = gxact->xid;
+		xid = XidFromFullTransactionId(gxact->full_xid);
 
 		buf = ProcessTwoPhaseBuffer(xid,
 									gxact->prepare_start_lsn,
@@ -2029,7 +2028,7 @@ RecoverPreparedTransactions(void)
 		TransactionId *subxids;
 		const char *gid;
 
-		xid = gxact->xid;
+		xid = XidFromFullTransactionId(gxact->full_xid);
 
 		/*
 		 * Reconstruct subtrans state for the transaction --- needed because
@@ -2050,7 +2049,7 @@ RecoverPreparedTransactions(void)
 				(errmsg("recovering prepared transaction %u from shared memory", xid)));
 
 		hdr = (TwoPhaseFileHeader *) buf;
-		Assert(TransactionIdEquals(hdr->xid, xid));
+		Assert(FullTransactionIdEquals(hdr->full_xid, gxact->full_xid));
 		bufptr = buf + MAXALIGN(sizeof(TwoPhaseFileHeader));
 		gid = (const char *) bufptr;
 		bufptr += MAXALIGN(hdr->gidlen);
@@ -2064,7 +2063,7 @@ RecoverPreparedTransactions(void)
 		 * Recreate its GXACT and dummy PGPROC. But, check whether it was
 		 * added in redo and already has a shmem entry for it.
 		 */
-		MarkAsPreparingGuts(gxact, xid, gid,
+		MarkAsPreparingGuts(gxact, gxact->full_xid, gid,
 							hdr->prepared_at,
 							hdr->owner, hdr->database);
 
@@ -2185,7 +2184,7 @@ ProcessTwoPhaseBuffer(TransactionId xid,
 
 	/* Deconstruct header */
 	hdr = (TwoPhaseFileHeader *) buf;
-	if (!TransactionIdEquals(hdr->xid, xid))
+	if (!TransactionIdEquals(XidFromFullTransactionId(hdr->full_xid), xid))
 	{
 		if (fromdisk)
 			ereport(ERROR,
@@ -2426,7 +2425,7 @@ PrepareRedoAdd(char *buf, XLogRecPtr start_lsn,
 	gxact->prepared_at = hdr->prepared_at;
 	gxact->prepare_start_lsn = start_lsn;
 	gxact->prepare_end_lsn = end_lsn;
-	gxact->xid = hdr->xid;
+	gxact->full_xid = hdr->full_xid;
 	gxact->owner = hdr->owner;
 	gxact->locking_backend = InvalidBackendId;
 	gxact->valid = false;
@@ -2445,7 +2444,8 @@ PrepareRedoAdd(char *buf, XLogRecPtr start_lsn,
 						   false /* backward */ , false /* WAL */ );
 	}
 
-	elog(DEBUG2, "added 2PC data in shared memory for transaction %u", gxact->xid);
+	elog(DEBUG2, "added 2PC data in shared memory for transaction %u",
+		 XidFromFullTransactionId(gxact->full_xid));
 }
 
 /*
@@ -2471,7 +2471,7 @@ PrepareRedoRemove(TransactionId xid, bool giveWarning)
 	{
 		gxact = TwoPhaseState->prepXacts[i];
 
-		if (gxact->xid == xid)
+		if (XidFromFullTransactionId(gxact->full_xid) == xid)
 		{
 			Assert(gxact->inredo);
 			found = true;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 1bbaeeebf4..9a61c53ff8 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -2413,8 +2413,8 @@ PrepareTransaction(void)
 	 * Reserve the GID for this transaction. This could fail if the requested
 	 * GID is invalid or already in use.
 	 */
-	gxact = MarkAsPreparing(xid, prepareGID, prepared_at,
-							GetUserId(), MyDatabaseId);
+	gxact = MarkAsPreparing(GetCurrentFullTransactionId(), prepareGID,
+							prepared_at, GetUserId(), MyDatabaseId);
 	prepareGID = NULL;
 
 	/*
diff --git a/src/include/access/transam.h b/src/include/access/transam.h
index 33fd052156..1128326aa7 100644
--- a/src/include/access/transam.h
+++ b/src/include/access/transam.h
@@ -48,6 +48,7 @@
 #define XidFromFullTransactionId(x)		((uint32) (x).value)
 #define U64FromFullTransactionId(x)		((x).value)
 #define FullTransactionIdPrecedes(a, b)	((a).value < (b).value)
+#define FullTransactionIdEquals(a, b)   ((a).value == (b).value)
 #define FullTransactionIdIsValid(x)		TransactionIdIsValid(XidFromFullTransactionId(x))
 #define InvalidFullTransactionId		FullTransactionIdFromEpochAndXid(0, InvalidTransactionId)
 
diff --git a/src/include/access/twophase.h b/src/include/access/twophase.h
index b9a531c96e..9a3cc573db 100644
--- a/src/include/access/twophase.h
+++ b/src/include/access/twophase.h
@@ -37,7 +37,8 @@ extern void PostPrepare_Twophase(void);
 extern PGPROC *TwoPhaseGetDummyProc(TransactionId xid, bool lock_held);
 extern BackendId TwoPhaseGetDummyBackendId(TransactionId xid, bool lock_held);
 
-extern GlobalTransaction MarkAsPreparing(TransactionId xid, const char *gid,
+extern GlobalTransaction MarkAsPreparing(FullTransactionId full_xid,
+										 const char *gid,
 										 TimestampTz prepared_at,
 										 Oid owner, Oid databaseid);
 
-- 
2.22.0

