diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c index c50f9c4bf6..96986ad954 100644 --- a/src/backend/access/transam/twophase.c +++ b/src/backend/access/transam/twophase.c @@ -338,18 +338,13 @@ AtAbort_Twophase(void) * resources held by the transaction yet. In those cases, the in-memory * state can be wrong, but it's too late to back out. */ + LWLockAcquire(TwoPhaseStateLock, LW_EXCLUSIVE); if (!MyLockedGxact->valid) - { RemoveGXact(MyLockedGxact); - } else - { - LWLockAcquire(TwoPhaseStateLock, LW_EXCLUSIVE); - MyLockedGxact->locking_backend = InvalidBackendId; + LWLockRelease(TwoPhaseStateLock); - LWLockRelease(TwoPhaseStateLock); - } MyLockedGxact = NULL; } @@ -624,6 +619,8 @@ LockGXact(const char *gid, Oid user) /* * RemoveGXact * Remove the prepared transaction from the shared memory array. + * Caller needs to hold an exclusive lock on TwoPhaseStateLock as + * data of TwoPhaseState gets updated. * * NB: caller should have already removed it from ProcArray */ @@ -632,8 +629,6 @@ RemoveGXact(GlobalTransaction gxact) { int i; - LWLockAcquire(TwoPhaseStateLock, LW_EXCLUSIVE); - for (i = 0; i < TwoPhaseState->numPrepXacts; i++) { if (gxact == TwoPhaseState->prepXacts[i]) @@ -646,8 +641,6 @@ RemoveGXact(GlobalTransaction gxact) gxact->next = TwoPhaseState->freeGXacts; TwoPhaseState->freeGXacts = gxact; - LWLockRelease(TwoPhaseStateLock); - return; } } @@ -1506,7 +1499,9 @@ FinishPreparedTransaction(const char *gid, bool isCommit) if (gxact->ondisk) RemoveTwoPhaseFile(xid, true); + LWLockAcquire(TwoPhaseStateLock, LW_EXCLUSIVE); RemoveGXact(gxact); + LWLockRelease(TwoPhaseStateLock); MyLockedGxact = NULL; pfree(buf); @@ -1781,6 +1776,9 @@ restoreTwoPhaseData(void) * If xids_p and nxids_p are not NULL, pointer to a palloc'd array of all * top-level xids is stored in *xids_p. The number of entries in the array * is returned in *nxids_p. + * + * An exclusive lock on TwoPhaseStateLock is taken for the duration of the + * scan of TwoPhaseState data as its may be updated. */ TransactionId PrescanPreparedTransactions(TransactionId **xids_p, int *nxids_p) @@ -1792,7 +1790,7 @@ PrescanPreparedTransactions(TransactionId **xids_p, int *nxids_p) int allocsize = 0; int i; - LWLockAcquire(TwoPhaseStateLock, LW_SHARED); + LWLockAcquire(TwoPhaseStateLock, LW_EXCLUSIVE); for (i = 0; i < TwoPhaseState->numPrepXacts; i++) { TransactionId xid; @@ -1861,13 +1859,16 @@ PrescanPreparedTransactions(TransactionId **xids_p, int *nxids_p) * The lack of calls to SubTransSetParent() calls here is by design; * those calls are made by RecoverPreparedTransactions() at the end of recovery * for those xacts that need this. + * + * An exclusive lock on TwoPhaseStateLock is taken for the duration of the + * scan of TwoPhaseState data as it may get updated. */ void StandbyRecoverPreparedTransactions(void) { int i; - LWLockAcquire(TwoPhaseStateLock, LW_SHARED); + LWLockAcquire(TwoPhaseStateLock, LW_EXCLUSIVE); for (i = 0; i < TwoPhaseState->numPrepXacts; i++) { TransactionId xid; @@ -2001,6 +2002,9 @@ RecoverPreparedTransactions(void) * * If setNextXid is true, set ShmemVariableCache->nextXid to the newest * value scanned. + * + * Caller needs to hold an exclusive lock on TwoPhaseStateLock as data + * of TwoPhaseState gets updated. */ static char * ProcessTwoPhaseBuffer(TransactionId xid, @@ -2361,6 +2365,9 @@ PrepareRedoAdd(char *buf, XLogRecPtr start_lsn, XLogRecPtr end_lsn) * Remove the corresponding gxact entry from TwoPhaseState. Also * remove the 2PC file if a prepared transaction was saved via * an earlier checkpoint. + * + * Caller needs to hold an exclusive lock on TwoPhaseStateLock as + * data of TwoPhaseState gets updated. */ void PrepareRedoRemove(TransactionId xid, bool giveWarning) @@ -2371,7 +2378,6 @@ PrepareRedoRemove(TransactionId xid, bool giveWarning) Assert(RecoveryInProgress()); - LWLockAcquire(TwoPhaseStateLock, LW_SHARED); for (i = 0; i < TwoPhaseState->numPrepXacts; i++) { gxact = TwoPhaseState->prepXacts[i]; @@ -2383,7 +2389,6 @@ PrepareRedoRemove(TransactionId xid, bool giveWarning) break; } } - LWLockRelease(TwoPhaseStateLock); /* * Just leave if there is nothing, this is expected during WAL replay.