From 589c0e98ae913a61d7f2833091a89d0f4e1ce556 Mon Sep 17 00:00:00 2001 From: Andrey Borodin Date: Sat, 19 Dec 2020 21:53:00 +0500 Subject: [PATCH v3 1/2] Wait for prepared xacts in CREATE INDEX CONCURRENTLY locks infrastructure --- src/backend/storage/lmgr/lmgr.c | 5 ++--- src/backend/storage/lmgr/lock.c | 37 ++++++++++++++++++++++----------- src/include/storage/lock.h | 5 +++++ 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c index 7409de9405..c1e8e76f41 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,7 @@ WaitForLockersMultiple(List *locktags, LOCKMODE lockmode, bool progress) { VirtualTransactionId *lockholders = lfirst(lc); - while (VirtualTransactionIdIsValid(*lockholders)) + while (VirtualTransactionIdIsValidOrPreparedXact(*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 d86566f455..d870396504 100644 --- a/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@ -2904,9 +2904,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) @@ -2931,15 +2929,17 @@ 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 *) @@ -3085,10 +3085,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; @@ -3108,7 +3109,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; @@ -4461,9 +4462,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 1c3e9c1999..dbd2a32678 100644 --- a/src/include/storage/lock.h +++ b/src/include/storage/lock.h @@ -70,6 +70,11 @@ typedef struct #define VirtualTransactionIdIsValid(vxid) \ (((vxid).backendId != InvalidBackendId) && \ LocalTransactionIdIsValid((vxid).localTransactionId)) +#define VirtualTransactionIdIsValidOrPreparedXact(vxid) \ + (((vxid).backendId == InvalidBackendId) || \ + 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)