From b7fda517fe7041c28b0bbd85ae19bb1a557eafb5 Mon Sep 17 00:00:00 2001
From: Andrey Borodin <amborodin@acm.org>
Date: Thu, 29 Jul 2021 17:26:44 +0500
Subject: [PATCH v6 3/3] Various debug stuff and fix in xidlist.xid

---
 contrib/amcheck/verify_nbtree.c  | 19 +++++++++++++++++--
 src/backend/commands/indexcmds.c | 10 +++++++++-
 src/backend/storage/lmgr/lock.c  | 30 +++++++++++++++++++-----------
 3 files changed, 45 insertions(+), 14 deletions(-)

diff --git a/contrib/amcheck/verify_nbtree.c b/contrib/amcheck/verify_nbtree.c
index fdfc320e84..3e1ac42051 100644
--- a/contrib/amcheck/verify_nbtree.c
+++ b/contrib/amcheck/verify_nbtree.c
@@ -2453,6 +2453,8 @@ bt_downlink_missing_check(BtreeCheckState *state, bool rightsplit,
  * REINDEX to repair corruption when there was an (undetected) broken HOT chain
  * also allows us to detect the corruption in many cases.
  */
+
+#include "storage/bufpage.h"
 static void
 bt_tuple_present_callback(Relation index, ItemPointer tid, Datum *values,
 						  bool *isnull, bool tupleIsAlive, void *checkstate)
@@ -2471,16 +2473,29 @@ bt_tuple_present_callback(Relation index, ItemPointer tid, Datum *values,
 	/* Probe Bloom filter -- tuple should be present */
 	if (bloom_lacks_element(state->filter, (unsigned char *) norm,
 							IndexTupleSize(norm)))
+	{
+		BlockIdData bid = tid->ip_blkid;
+		Buffer buf = ReadBufferExtended(state->heaprel, MAIN_FORKNUM, BlockIdGetBlockNumber(&bid), RBM_NORMAL, NULL);
+		LockBuffer(buf, BUFFER_LOCK_SHARE);
+		Page page = BufferGetPage(buf);
+
+		HeapTupleHeader tuphdr = (HeapTupleHeader) PageGetItem(page, PageGetItemId(page,tid->ip_posid));
+		
+		LockBuffer(buf, BUFFER_LOCK_UNLOCK);
+		ReleaseBuffer(buf);
 		ereport(ERROR,
 				(errcode(ERRCODE_DATA_CORRUPTED),
-				 errmsg("heap tuple (%u,%u) from table \"%s\" lacks matching index tuple within index \"%s\"",
+				 errmsg("heap tuple (%u,%u) from table \"%s\" lacks matching index tuple within index \"%s\" xmin %d xmax %d",
 						ItemPointerGetBlockNumber(&(itup->t_tid)),
 						ItemPointerGetOffsetNumber(&(itup->t_tid)),
 						RelationGetRelationName(state->heaprel),
-						RelationGetRelationName(state->rel)),
+						RelationGetRelationName(state->rel),
+						HeapTupleHeaderGetRawXmin(tuphdr),
+						HeapTupleHeaderGetRawXmax(tuphdr)),
 				 !state->readonly
 				 ? errhint("Retrying verification using the function bt_index_parent_check() might provide a more specific error.")
 				 : 0));
+	}
 
 	state->heaptuplespresent++;
 	pfree(itup);
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 76774dce06..51cc484e42 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -1536,7 +1536,6 @@ DefineIndex(Oid relationId,
 	 */
 	pgstat_progress_update_param(PROGRESS_CREATEIDX_PHASE,
 								 PROGRESS_CREATEIDX_PHASE_WAIT_2);
-	WaitForLockers(heaplocktag, ShareLock, true);
 
 	/*
 	 * Now take the "reference snapshot" that will be used by validate_index()
@@ -1556,6 +1555,8 @@ DefineIndex(Oid relationId,
 	snapshot = RegisterSnapshot(GetTransactionSnapshot());
 	PushActiveSnapshot(snapshot);
 
+	WaitForLockers(heaplocktag, ShareLock, true);
+
 	/*
 	 * Scan the index and the heap, insert any missing index entries.
 	 */
@@ -3519,6 +3520,7 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
 	 * for efficiency.
 	 */
 
+	elog(WARNING, "Phase 1");
 	/*
 	 * Phase 1 of REINDEX CONCURRENTLY
 	 *
@@ -3669,6 +3671,7 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
 	 * to set the PROC_IN_SAFE_IC flag here.
 	 */
 
+	elog(WARNING, "Phase 2");
 	/*
 	 * Phase 2 of REINDEX CONCURRENTLY
 	 *
@@ -3730,6 +3733,7 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
 	 * need to set the PROC_IN_SAFE_IC flag here.
 	 */
 
+	elog(WARNING, "Phase 3");
 	/*
 	 * Phase 3 of REINDEX CONCURRENTLY
 	 *
@@ -3816,6 +3820,7 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
 		CommitTransactionCommand();
 	}
 
+	elog(WARNING, "Phase 4");
 	/*
 	 * Phase 4 of REINDEX CONCURRENTLY
 	 *
@@ -3889,6 +3894,7 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
 	 * done, and that lasts for a very short period.
 	 */
 
+	elog(WARNING, "Phase 5");
 	/*
 	 * Phase 5 of REINDEX CONCURRENTLY
 	 *
@@ -3925,6 +3931,7 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
 	 * done, and that lasts for a very short period.
 	 */
 
+	elog(WARNING, "Phase 6");
 	/*
 	 * Phase 6 of REINDEX CONCURRENTLY
 	 *
@@ -3962,6 +3969,7 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
 
 	PopActiveSnapshot();
 	CommitTransactionCommand();
+	elog(WARNING, "Phase Final");
 
 	/*
 	 * Finally, release the session-level lock on the table.
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 55efb33a7b..3644d3f4cf 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -3019,13 +3019,13 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
 				GET_VXID_FROM_PGPROC(vxid, *proc);
 
 				/* Prefer real Xid over local Xid */
-				if (TransactionIdIsValid(proc->xid))
+				/*if (TransactionIdIsValid(proc->xid))
 				{
 					vxids[count].backendId = InvalidBackendId;
 					vxids[count].localTransactionId = proc->xid;
 					count++;
 				}
-				else if (VirtualTransactionIdIsValid(vxid))
+				else */if (VirtualTransactionIdIsValid(vxid))
 					vxids[count++] = vxid;
 				/* else, xact already committed or aborted */
 
@@ -3087,13 +3087,13 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
 				GET_VXID_FROM_PGPROC(vxid, *proc);
 
 				/* Prefer real Xid over local Xid */
-				if (TransactionIdIsValid(proc->xid))
+				/*if (TransactionIdIsValid(proc->xid))
 				{
 					vxids[count].backendId = InvalidBackendId;
 					vxids[count].localTransactionId = proc->xid;
 					count++;
 				}
-				else if (VirtualTransactionIdIsValid(vxid))
+				else */if (VirtualTransactionIdIsValid(vxid))
 				{
 					int			i;
 
@@ -4468,7 +4468,7 @@ VirtualXactLockTableCleanup(void)
  *		Wait for xid completition if have xid. Otherwise try to find xid among
  *		fake procarray entries.
  */
-static bool PreparedXactLock(VirtualTransactionId vxid, TransactionId xid, bool wait)
+static bool PreparedXactLock(VirtualTransactionId vxid, TransactionId xidx, bool wait)
 {
 	LockAcquireResult	lar;
 	LOCKTAG				tag;
@@ -4477,10 +4477,11 @@ static bool PreparedXactLock(VirtualTransactionId vxid, TransactionId xid, bool
 	/* Questionable heuristics */
 	if (max_prepared_xacts == 0)
 		return true;
+	elog(WARNING,"XXX: PreparedXactLock xid %d, vxid %d/%d",xidx, vxid.backendId, vxid.localTransactionId);	// Remove this line
 
-	if (TransactionIdIsValid(xid))
+	if (TransactionIdIsValid(xidx))
 	{
-		xidlist.xid = xid;
+		xidlist.xid = xidx;
 		xidlist.next = NULL;
 	}
 	else
@@ -4488,18 +4489,19 @@ static bool PreparedXactLock(VirtualTransactionId vxid, TransactionId xid, bool
 		/* We must search for vxids in 2pc state */
 		/* XXX: O(N*N) complexity where N is number of prepared xacts */
 		xidlist = TwoPhaseGetXidByVXid(vxid);
-		elog(NOTICE,"XXX: Sucessfully found xid by vxid");	// Remove this line
+		elog(WARNING,"XXX: Sucessfully found xid by vxid %d", xidlist.xid);	// Remove this line
 	}
 
 	while (true)
 	{
 		if (TransactionIdIsValid(xidlist.xid))
 		{
-			SET_LOCKTAG_TRANSACTION(tag, xid);
+			SET_LOCKTAG_TRANSACTION(tag, xidlist.xid);
 			lar = LockAcquire(&tag, ShareLock, false, !wait);
 			if (lar != LOCKACQUIRE_NOT_AVAIL)
 				LockRelease(&tag, ShareLock, false);
-			return lar != LOCKACQUIRE_NOT_AVAIL;
+			if (lar == LOCKACQUIRE_NOT_AVAIL)
+				return false;
 		}
 		if (xidlist.next == NULL)
 			return true;
@@ -4524,6 +4526,7 @@ VirtualXactLock(VirtualTransactionId vxid, bool wait)
 	TransactionId	xid = InvalidTransactionId;
 
 	Assert(VirtualTransactionIdIsValid(vxid));
+	elog(WARNING,"XXX: VirtualXactLock vxid %d/%d", vxid.backendId, vxid.localTransactionId);	// Remove this line
 
 	/*
 	 * Already prepared transactions don't hold vxid locks.  The
@@ -4544,7 +4547,10 @@ VirtualXactLock(VirtualTransactionId vxid, bool wait)
 	 */
 	proc = BackendIdGetProc(vxid.backendId);
 	if (proc == NULL)
+	{
+		elog(WARNING,"Backend is gone");
 		return PreparedXactLock(vxid, InvalidTransactionId, wait);
+	}
 
 	/*
 	 * We must acquire this lock before checking the backendId and lxid
@@ -4557,12 +4563,13 @@ VirtualXactLock(VirtualTransactionId vxid, bool wait)
 	if (proc->backendId != vxid.backendId
 		|| proc->fpLocalTransactionId != vxid.localTransactionId)
 	{
+		elog(WARNING,"Backend is doing something else");
 		LWLockRelease(&proc->fpInfoLock);
 		return PreparedXactLock(vxid, InvalidTransactionId, wait);
 	}
 
 	/* Save the xid to test if transaction coverted to 2pc later */
-	xid = proc->xid;
+	xid = proc->xid;	
 
 	/*
 	 * If we aren't asked to wait, there's no need to set up a lock table
@@ -4615,6 +4622,7 @@ VirtualXactLock(VirtualTransactionId vxid, bool wait)
 	(void) LockAcquire(&tag, ShareLock, false, false);
 
 	LockRelease(&tag, ShareLock, false);
+	elog(WARNING,"Finally waiting on xid %d", xid);
 	return PreparedXactLock(vxid, xid, wait);;
 }
 
-- 
2.24.3 (Apple Git-128)

