Skip to content

Commit 5cf2307

Browse files
committed
Fix TwoPhaseGetDummyBackendId().
This was broken in commit ed0b409, 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.
1 parent 7d947ec commit 5cf2307

File tree

1 file changed

+46
-30
lines changed

1 file changed

+46
-30
lines changed

src/backend/access/transam/twophase.c

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@ int max_prepared_xacts = 0;
107107

108108
typedef struct GlobalTransactionData
109109
{
110-
GlobalTransaction next;
111-
int pgprocno; /* dummy proc */
110+
GlobalTransaction next; /* list link for free list */
111+
int pgprocno; /* ID of associated dummy PGPROC */
112112
BackendId dummyBackendId; /* similar to backend id for backends */
113113
TimestampTz prepared_at; /* time of preparation */
114114
XLogRecPtr prepare_lsn; /* XLOG offset of prepare record */
@@ -202,10 +202,13 @@ TwoPhaseShmemInit(void)
202202
sizeof(GlobalTransaction) * max_prepared_xacts));
203203
for (i = 0; i < max_prepared_xacts; i++)
204204
{
205-
gxacts[i].pgprocno = PreparedXactProcs[i].pgprocno;
205+
/* insert into linked list */
206206
gxacts[i].next = TwoPhaseState->freeGXacts;
207207
TwoPhaseState->freeGXacts = &gxacts[i];
208208

209+
/* associate it with a PGPROC assigned by InitProcGlobal */
210+
gxacts[i].pgprocno = PreparedXactProcs[i].pgprocno;
211+
209212
/*
210213
* Assign a unique ID for each dummy proc, so that the range of
211214
* dummy backend IDs immediately follows the range of normal
@@ -300,7 +303,7 @@ MarkAsPreparing(TransactionId xid, const char *gid,
300303
errhint("Increase max_prepared_transactions (currently %d).",
301304
max_prepared_xacts)));
302305
gxact = TwoPhaseState->freeGXacts;
303-
TwoPhaseState->freeGXacts = (GlobalTransaction) gxact->next;
306+
TwoPhaseState->freeGXacts = gxact->next;
304307

305308
proc = &ProcGlobal->allProcs[gxact->pgprocno];
306309
pgxact = &ProcGlobal->allPgXact[gxact->pgprocno];
@@ -680,40 +683,25 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
680683
}
681684

682685
/*
683-
* TwoPhaseGetDummyProc
684-
* Get the dummy backend ID for prepared transaction specified by XID
685-
*
686-
* Dummy backend IDs are similar to real backend IDs of real backends.
687-
* They start at MaxBackends + 1, and are unique across all currently active
688-
* real backends and prepared transactions.
686+
* TwoPhaseGetGXact
687+
* Get the GlobalTransaction struct for a prepared transaction
688+
* specified by XID
689689
*/
690-
BackendId
691-
TwoPhaseGetDummyBackendId(TransactionId xid)
692-
{
693-
PGPROC *proc = TwoPhaseGetDummyProc(xid);
694-
695-
return ((GlobalTransaction) proc)->dummyBackendId;
696-
}
697-
698-
/*
699-
* TwoPhaseGetDummyProc
700-
* Get the PGPROC that represents a prepared transaction specified by XID
701-
*/
702-
PGPROC *
703-
TwoPhaseGetDummyProc(TransactionId xid)
690+
static GlobalTransaction
691+
TwoPhaseGetGXact(TransactionId xid)
704692
{
705-
PGPROC *result = NULL;
693+
GlobalTransaction result = NULL;
706694
int i;
707695

708696
static TransactionId cached_xid = InvalidTransactionId;
709-
static PGPROC *cached_proc = NULL;
697+
static GlobalTransaction cached_gxact = NULL;
710698

711699
/*
712700
* During a recovery, COMMIT PREPARED, or ABORT PREPARED, we'll be called
713701
* repeatedly for the same XID. We can save work with a simple cache.
714702
*/
715703
if (xid == cached_xid)
716-
return cached_proc;
704+
return cached_gxact;
717705

718706
LWLockAcquire(TwoPhaseStateLock, LW_SHARED);
719707

@@ -724,22 +712,50 @@ TwoPhaseGetDummyProc(TransactionId xid)
724712

725713
if (pgxact->xid == xid)
726714
{
727-
result = &ProcGlobal->allProcs[gxact->pgprocno];
715+
result = gxact;
728716
break;
729717
}
730718
}
731719

732720
LWLockRelease(TwoPhaseStateLock);
733721

734722
if (result == NULL) /* should not happen */
735-
elog(ERROR, "failed to find dummy PGPROC for xid %u", xid);
723+
elog(ERROR, "failed to find GlobalTransaction for xid %u", xid);
736724

737725
cached_xid = xid;
738-
cached_proc = result;
726+
cached_gxact = result;
739727

740728
return result;
741729
}
742730

731+
/*
732+
* TwoPhaseGetDummyProc
733+
* Get the dummy backend ID for prepared transaction specified by XID
734+
*
735+
* Dummy backend IDs are similar to real backend IDs of real backends.
736+
* They start at MaxBackends + 1, and are unique across all currently active
737+
* real backends and prepared transactions.
738+
*/
739+
BackendId
740+
TwoPhaseGetDummyBackendId(TransactionId xid)
741+
{
742+
GlobalTransaction gxact = TwoPhaseGetGXact(xid);
743+
744+
return gxact->dummyBackendId;
745+
}
746+
747+
/*
748+
* TwoPhaseGetDummyProc
749+
* Get the PGPROC that represents a prepared transaction specified by XID
750+
*/
751+
PGPROC *
752+
TwoPhaseGetDummyProc(TransactionId xid)
753+
{
754+
GlobalTransaction gxact = TwoPhaseGetGXact(xid);
755+
756+
return &ProcGlobal->allProcs[gxact->pgprocno];
757+
}
758+
743759
/************************************************************************/
744760
/* State file support */
745761
/************************************************************************/

0 commit comments

Comments
 (0)