mirror of
https://github.com/postgres/postgres.git
synced 2025-06-05 00:02:04 -04:00
Fix TwoPhaseGetDummyBackendId().
This was broken in commit ed0b409d22346b1b027a4c2099ca66984d94b6dd, 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.
This commit is contained in:
parent
7d947ec82a
commit
5cf2307c98
@ -107,8 +107,8 @@ int max_prepared_xacts = 0;
|
|||||||
|
|
||||||
typedef struct GlobalTransactionData
|
typedef struct GlobalTransactionData
|
||||||
{
|
{
|
||||||
GlobalTransaction next;
|
GlobalTransaction next; /* list link for free list */
|
||||||
int pgprocno; /* dummy proc */
|
int pgprocno; /* ID of associated dummy PGPROC */
|
||||||
BackendId dummyBackendId; /* similar to backend id for backends */
|
BackendId dummyBackendId; /* similar to backend id for backends */
|
||||||
TimestampTz prepared_at; /* time of preparation */
|
TimestampTz prepared_at; /* time of preparation */
|
||||||
XLogRecPtr prepare_lsn; /* XLOG offset of prepare record */
|
XLogRecPtr prepare_lsn; /* XLOG offset of prepare record */
|
||||||
@ -202,10 +202,13 @@ TwoPhaseShmemInit(void)
|
|||||||
sizeof(GlobalTransaction) * max_prepared_xacts));
|
sizeof(GlobalTransaction) * max_prepared_xacts));
|
||||||
for (i = 0; i < max_prepared_xacts; i++)
|
for (i = 0; i < max_prepared_xacts; i++)
|
||||||
{
|
{
|
||||||
gxacts[i].pgprocno = PreparedXactProcs[i].pgprocno;
|
/* insert into linked list */
|
||||||
gxacts[i].next = TwoPhaseState->freeGXacts;
|
gxacts[i].next = TwoPhaseState->freeGXacts;
|
||||||
TwoPhaseState->freeGXacts = &gxacts[i];
|
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
|
* Assign a unique ID for each dummy proc, so that the range of
|
||||||
* dummy backend IDs immediately follows the range of normal
|
* dummy backend IDs immediately follows the range of normal
|
||||||
@ -300,7 +303,7 @@ MarkAsPreparing(TransactionId xid, const char *gid,
|
|||||||
errhint("Increase max_prepared_transactions (currently %d).",
|
errhint("Increase max_prepared_transactions (currently %d).",
|
||||||
max_prepared_xacts)));
|
max_prepared_xacts)));
|
||||||
gxact = TwoPhaseState->freeGXacts;
|
gxact = TwoPhaseState->freeGXacts;
|
||||||
TwoPhaseState->freeGXacts = (GlobalTransaction) gxact->next;
|
TwoPhaseState->freeGXacts = gxact->next;
|
||||||
|
|
||||||
proc = &ProcGlobal->allProcs[gxact->pgprocno];
|
proc = &ProcGlobal->allProcs[gxact->pgprocno];
|
||||||
pgxact = &ProcGlobal->allPgXact[gxact->pgprocno];
|
pgxact = &ProcGlobal->allPgXact[gxact->pgprocno];
|
||||||
@ -680,40 +683,25 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TwoPhaseGetDummyProc
|
* TwoPhaseGetGXact
|
||||||
* Get the dummy backend ID for prepared transaction specified by XID
|
* Get the GlobalTransaction struct for a 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
|
static GlobalTransaction
|
||||||
TwoPhaseGetDummyBackendId(TransactionId xid)
|
TwoPhaseGetGXact(TransactionId xid)
|
||||||
{
|
{
|
||||||
PGPROC *proc = TwoPhaseGetDummyProc(xid);
|
GlobalTransaction result = NULL;
|
||||||
|
|
||||||
return ((GlobalTransaction) proc)->dummyBackendId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* TwoPhaseGetDummyProc
|
|
||||||
* Get the PGPROC that represents a prepared transaction specified by XID
|
|
||||||
*/
|
|
||||||
PGPROC *
|
|
||||||
TwoPhaseGetDummyProc(TransactionId xid)
|
|
||||||
{
|
|
||||||
PGPROC *result = NULL;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
static TransactionId cached_xid = InvalidTransactionId;
|
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
|
* 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.
|
* repeatedly for the same XID. We can save work with a simple cache.
|
||||||
*/
|
*/
|
||||||
if (xid == cached_xid)
|
if (xid == cached_xid)
|
||||||
return cached_proc;
|
return cached_gxact;
|
||||||
|
|
||||||
LWLockAcquire(TwoPhaseStateLock, LW_SHARED);
|
LWLockAcquire(TwoPhaseStateLock, LW_SHARED);
|
||||||
|
|
||||||
@ -724,7 +712,7 @@ TwoPhaseGetDummyProc(TransactionId xid)
|
|||||||
|
|
||||||
if (pgxact->xid == xid)
|
if (pgxact->xid == xid)
|
||||||
{
|
{
|
||||||
result = &ProcGlobal->allProcs[gxact->pgprocno];
|
result = gxact;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -732,14 +720,42 @@ TwoPhaseGetDummyProc(TransactionId xid)
|
|||||||
LWLockRelease(TwoPhaseStateLock);
|
LWLockRelease(TwoPhaseStateLock);
|
||||||
|
|
||||||
if (result == NULL) /* should not happen */
|
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_xid = xid;
|
||||||
cached_proc = result;
|
cached_gxact = result;
|
||||||
|
|
||||||
return 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 */
|
/* State file support */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user