Skip to content

Commit db10834

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 5ebaaa4 commit db10834

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
@@ -108,8 +108,8 @@ int max_prepared_xacts = 0;
108108

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

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

306309
proc = &ProcGlobal->allProcs[gxact->pgprocno];
307310
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)