v5-0001-Wait-for-prepared-xacts-in-CREATE-INDEX-CONCURREN.patch

application/octet-stream

Filename: v5-0001-Wait-for-prepared-xacts-in-CREATE-INDEX-CONCURREN.patch
Type: application/octet-stream
Part: 0
Message: Re: CREATE INDEX CONCURRENTLY does not index prepared xact's data

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: format-patch
Series: patch v5-0001
Subject: Wait for prepared xacts in CREATE INDEX CONCURRENTLY locks infrastructure
File+
src/backend/storage/lmgr/lmgr.c 3 3
src/backend/storage/lmgr/lock.c 26 13
src/include/storage/lock.h 3 2
From 30ec43e1054e4fae47f9221bb834281abb7fc5ac Mon Sep 17 00:00:00 2001
From: Andrey Borodin <amborodin@acm.org>
Date: Sat, 19 Dec 2020 21:53:00 +0500
Subject: [PATCH v5 1/2] Wait for prepared xacts in CREATE INDEX CONCURRENTLY
 locks infrastructure

---
 src/backend/storage/lmgr/lmgr.c |  6 ++---
 src/backend/storage/lmgr/lock.c | 39 ++++++++++++++++++++++-----------
 src/include/storage/lock.h      |  5 +++--
 3 files changed, 32 insertions(+), 18 deletions(-)

diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c
index 7407672c9d..07f75d8e06 100644
--- a/src/backend/storage/lmgr/lmgr.c
+++ b/src/backend/storage/lmgr/lmgr.c
@@ -904,8 +904,7 @@ WaitForLockersMultiple(List *locktags, LOCKMODE lockmode, bool progress)
 
 	/*
 	 * Note: GetLockConflicts() never reports our own xid, hence we need not
-	 * check for that.  Also, prepared xacts are not reported, which is fine
-	 * since they certainly aren't going to do anything anymore.
+	 * check for that.  Also, prepared xacts are reported and awaited.
 	 */
 
 	/* Finally wait for each such transaction to complete */
@@ -913,7 +912,8 @@ WaitForLockersMultiple(List *locktags, LOCKMODE lockmode, bool progress)
 	{
 		VirtualTransactionId *lockholders = lfirst(lc);
 
-		while (VirtualTransactionIdIsValid(*lockholders))
+		while (VirtualTransactionIdIsValid(*lockholders) ||
+				VirtualTransactionIdIsPreparedXact(*lockholders))
 		{
 			/* If requested, publish who we're going to wait for. */
 			if (progress)
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 20e50247ea..6435e28422 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -2903,9 +2903,7 @@ FastPathGetRelationLockEntry(LOCALLOCK *locallock)
  * so use of this function has to be thought about carefully.
  *
  * Note we never include the current xact's vxid in the result array,
- * since an xact never blocks itself.  Also, prepared transactions are
- * ignored, which is a bit more debatable but is appropriate for current
- * uses of the result.
+ * since an xact never blocks itself.
  */
 VirtualTransactionId *
 GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
@@ -2930,19 +2928,21 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
 
 	/*
 	 * Allocate memory to store results, and fill with InvalidVXID.  We only
-	 * need enough space for MaxBackends + a terminator, since prepared xacts
-	 * don't count. InHotStandby allocate once in TopMemoryContext.
+	 * need enough space for MaxBackends + max_prepared_xacts + a
+	 * terminator. InHotStandby allocate once in TopMemoryContext.
 	 */
 	if (InHotStandby)
 	{
 		if (vxids == NULL)
 			vxids = (VirtualTransactionId *)
 				MemoryContextAlloc(TopMemoryContext,
-								   sizeof(VirtualTransactionId) * (MaxBackends + 1));
+								   sizeof(VirtualTransactionId) * (MaxBackends +
+								   max_prepared_xacts + 1));
 	}
 	else
 		vxids = (VirtualTransactionId *)
-			palloc0(sizeof(VirtualTransactionId) * (MaxBackends + 1));
+			palloc0(sizeof(VirtualTransactionId) * (MaxBackends +
+					max_prepared_xacts + 1));
 
 	/* Compute hash code and partition lock, and look up conflicting modes. */
 	hashcode = LockTagHashCode(locktag);
@@ -3084,10 +3084,11 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
 
 				/*
 				 * If we see an invalid VXID, then either the xact has already
-				 * committed (or aborted), or it's a prepared xact.  In either
-				 * case we may ignore it.
+				 * committed (or aborted), or it's a prepared xact. We take
+				 * prepared xacts into account too.
 				 */
-				if (VirtualTransactionIdIsValid(vxid))
+				if (VirtualTransactionIdIsValid(vxid)
+					|| VirtualTransactionIdIsPreparedXact(vxid))
 				{
 					int			i;
 
@@ -3107,7 +3108,7 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
 
 	LWLockRelease(partitionLock);
 
-	if (count > MaxBackends)	/* should never happen */
+	if (count > MaxBackends + max_prepared_xacts)	/* should never happen */
 		elog(PANIC, "too many conflicting locks found");
 
 	vxids[count].backendId = InvalidBackendId;
@@ -4460,9 +4461,21 @@ bool
 VirtualXactLock(VirtualTransactionId vxid, bool wait)
 {
 	LOCKTAG		tag;
-	PGPROC	   *proc;
+	PGPROC	   *proc = NULL;
 
-	Assert(VirtualTransactionIdIsValid(vxid));
+	Assert(VirtualTransactionIdIsValid(vxid) ||
+			VirtualTransactionIdIsPreparedXact(vxid));
+
+	if (VirtualTransactionIdIsPreparedXact(vxid))
+	{
+		LockAcquireResult lar;
+		/* If it's prepared xact - just wait for it */
+		SET_LOCKTAG_TRANSACTION(tag, vxid.localTransactionId);
+		lar = LockAcquire(&tag, ShareLock, false, !wait);
+		if (lar == LOCKACQUIRE_OK)
+			LockRelease(&tag, ShareLock, false);
+		return lar != LOCKACQUIRE_NOT_AVAIL;
+	}
 
 	SET_LOCKTAG_VIRTUALTRANSACTION(tag, vxid);
 
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index 2e6ef174e9..221f23e5a6 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -68,8 +68,9 @@ typedef struct
 #define InvalidLocalTransactionId		0
 #define LocalTransactionIdIsValid(lxid) ((lxid) != InvalidLocalTransactionId)
 #define VirtualTransactionIdIsValid(vxid) \
-	(((vxid).backendId != InvalidBackendId) && \
-	 LocalTransactionIdIsValid((vxid).localTransactionId))
+	(LocalTransactionIdIsValid((vxid).localTransactionId))
+#define VirtualTransactionIdIsPreparedXact(vxid) \
+	((vxid).backendId == InvalidBackendId)
 #define VirtualTransactionIdEquals(vxid1, vxid2) \
 	((vxid1).backendId == (vxid2).backendId && \
 	 (vxid1).localTransactionId == (vxid2).localTransactionId)
-- 
2.24.3 (Apple Git-128)