Commit db108349 authored by Tom Lane's avatar Tom Lane

Fix TwoPhaseGetDummyBackendId().

This was broken in commit ed0b409d,
which revised the GlobalTransactionData struct to not include the
associated PGPROC as its first member, but overlooked one place where
a cast was used in reliance on that equivalence.

The most effective way of fixing this seems to be to create a new function
that looks up the GlobalTransactionData struct given the XID, and make
both TwoPhaseGetDummyBackendId and TwoPhaseGetDummyProc rely on that.

Per report from Robert Ross.
parent 5ebaaa49
......@@ -108,8 +108,8 @@ int max_prepared_xacts = 0;
typedef struct GlobalTransactionData
{
GlobalTransaction next;
int pgprocno; /* dummy proc */
GlobalTransaction next; /* list link for free list */
int pgprocno; /* ID of associated dummy PGPROC */
BackendId dummyBackendId; /* similar to backend id for backends */
TimestampTz prepared_at; /* time of preparation */
XLogRecPtr prepare_lsn; /* XLOG offset of prepare record */
......@@ -203,10 +203,13 @@ TwoPhaseShmemInit(void)
sizeof(GlobalTransaction) * max_prepared_xacts));
for (i = 0; i < max_prepared_xacts; i++)
{
gxacts[i].pgprocno = PreparedXactProcs[i].pgprocno;
/* insert into linked list */
gxacts[i].next = TwoPhaseState->freeGXacts;
TwoPhaseState->freeGXacts = &gxacts[i];
/* associate it with a PGPROC assigned by InitProcGlobal */
gxacts[i].pgprocno = PreparedXactProcs[i].pgprocno;
/*
* Assign a unique ID for each dummy proc, so that the range of
* dummy backend IDs immediately follows the range of normal
......@@ -301,7 +304,7 @@ MarkAsPreparing(TransactionId xid, const char *gid,
errhint("Increase max_prepared_transactions (currently %d).",
max_prepared_xacts)));
gxact = TwoPhaseState->freeGXacts;
TwoPhaseState->freeGXacts = (GlobalTransaction) gxact->next;
TwoPhaseState->freeGXacts = gxact->next;
proc = &ProcGlobal->allProcs[gxact->pgprocno];
pgxact = &ProcGlobal->allPgXact[gxact->pgprocno];
......@@ -680,40 +683,25 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
}
/*
* TwoPhaseGetDummyProc
* Get the dummy backend ID for prepared transaction specified by XID
*
* Dummy backend IDs are similar to real backend IDs of real backends.
* They start at MaxBackends + 1, and are unique across all currently active
* real backends and prepared transactions.
* TwoPhaseGetGXact
* Get the GlobalTransaction struct for a prepared transaction
* specified by XID
*/
BackendId
TwoPhaseGetDummyBackendId(TransactionId xid)
{
PGPROC *proc = TwoPhaseGetDummyProc(xid);
return ((GlobalTransaction) proc)->dummyBackendId;
}
/*
* TwoPhaseGetDummyProc
* Get the PGPROC that represents a prepared transaction specified by XID
*/
PGPROC *
TwoPhaseGetDummyProc(TransactionId xid)
static GlobalTransaction
TwoPhaseGetGXact(TransactionId xid)
{
PGPROC *result = NULL;
GlobalTransaction result = NULL;
int i;
static TransactionId cached_xid = InvalidTransactionId;
static PGPROC *cached_proc = NULL;
static GlobalTransaction cached_gxact = NULL;
/*
* During a recovery, COMMIT PREPARED, or ABORT PREPARED, we'll be called
* repeatedly for the same XID. We can save work with a simple cache.
*/
if (xid == cached_xid)
return cached_proc;
return cached_gxact;
LWLockAcquire(TwoPhaseStateLock, LW_SHARED);
......@@ -724,7 +712,7 @@ TwoPhaseGetDummyProc(TransactionId xid)
if (pgxact->xid == xid)
{
result = &ProcGlobal->allProcs[gxact->pgprocno];
result = gxact;
break;
}
}
......@@ -732,14 +720,42 @@ TwoPhaseGetDummyProc(TransactionId xid)
LWLockRelease(TwoPhaseStateLock);
if (result == NULL) /* should not happen */
elog(ERROR, "failed to find dummy PGPROC for xid %u", xid);
elog(ERROR, "failed to find GlobalTransaction for xid %u", xid);
cached_xid = xid;
cached_proc = result;
cached_gxact = result;
return result;
}
/*
* TwoPhaseGetDummyProc
* Get the dummy backend ID for prepared transaction specified by XID
*
* Dummy backend IDs are similar to real backend IDs of real backends.
* They start at MaxBackends + 1, and are unique across all currently active
* real backends and prepared transactions.
*/
BackendId
TwoPhaseGetDummyBackendId(TransactionId xid)
{
GlobalTransaction gxact = TwoPhaseGetGXact(xid);
return gxact->dummyBackendId;
}
/*
* TwoPhaseGetDummyProc
* Get the PGPROC that represents a prepared transaction specified by XID
*/
PGPROC *
TwoPhaseGetDummyProc(TransactionId xid)
{
GlobalTransaction gxact = TwoPhaseGetGXact(xid);
return &ProcGlobal->allProcs[gxact->pgprocno];
}
/************************************************************************/
/* State file support */
/************************************************************************/
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment