Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit aa203e7

Browse files
Don’t push nextid too far forwards in recovery
Doing so allows various crash possibilities. Fix by avoiding having PrescanPreparedTransactions() increment ShmemVariableCache->nextXid when it has no 2PC files Bug found by Jeff Janes, diagnosis and patch by Pavan Deolasee, then patch re-designed for clarity and full accuracy by Michael Paquier. Reported-by: Jeff Janes Author: Pavan Deolasee, Michael Paquier Discussion: https://postgr.es/m/CAMkU=1zMLnH_i1-PVQ-biZzvNx7VcuatriquEnh7HNk6K8Ss3Q@mail.gmail.com
1 parent 51175f3 commit aa203e7

File tree

1 file changed

+36
-41
lines changed

1 file changed

+36
-41
lines changed

src/backend/access/transam/twophase.c

Lines changed: 36 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ static void XlogReadTwoPhaseData(XLogRecPtr lsn, char **buf, int *len);
222222
static char *ProcessTwoPhaseBuffer(TransactionId xid,
223223
XLogRecPtr prepare_start_lsn,
224224
bool fromdisk, bool overwriteOK, bool setParent,
225-
TransactionId *result, TransactionId *maxsubxid);
225+
bool setNextXid);
226226
static void MarkAsPreparingGuts(GlobalTransaction gxact, TransactionId xid,
227227
const char *gid, TimestampTz prepared_at, Oid owner,
228228
Oid databaseid);
@@ -1744,7 +1744,7 @@ restoreTwoPhaseData(void)
17441744

17451745
buf = ProcessTwoPhaseBuffer(xid, InvalidXLogRecPtr,
17461746
true, false, false,
1747-
NULL, NULL);
1747+
false);
17481748
if (buf == NULL)
17491749
continue;
17501750

@@ -1786,7 +1786,6 @@ PrescanPreparedTransactions(TransactionId **xids_p, int *nxids_p)
17861786
{
17871787
TransactionId origNextXid = ShmemVariableCache->nextXid;
17881788
TransactionId result = origNextXid;
1789-
TransactionId maxsubxid = origNextXid;
17901789
TransactionId *xids = NULL;
17911790
int nxids = 0;
17921791
int allocsize = 0;
@@ -1806,11 +1805,18 @@ PrescanPreparedTransactions(TransactionId **xids_p, int *nxids_p)
18061805
buf = ProcessTwoPhaseBuffer(xid,
18071806
gxact->prepare_start_lsn,
18081807
gxact->ondisk, false, false,
1809-
&result, &maxsubxid);
1808+
true);
18101809

18111810
if (buf == NULL)
18121811
continue;
18131812

1813+
/*
1814+
* OK, we think this file is valid. Incorporate xid into the
1815+
* running-minimum result.
1816+
*/
1817+
if (TransactionIdPrecedes(xid, result))
1818+
result = xid;
1819+
18141820
if (xids_p)
18151821
{
18161822
if (nxids == allocsize)
@@ -1839,15 +1845,6 @@ PrescanPreparedTransactions(TransactionId **xids_p, int *nxids_p)
18391845
*nxids_p = nxids;
18401846
}
18411847

1842-
/* update nextXid if needed */
1843-
if (TransactionIdFollowsOrEquals(maxsubxid, ShmemVariableCache->nextXid))
1844-
{
1845-
LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
1846-
ShmemVariableCache->nextXid = maxsubxid;
1847-
TransactionIdAdvance(ShmemVariableCache->nextXid);
1848-
LWLockRelease(XidGenLock);
1849-
}
1850-
18511848
return result;
18521849
}
18531850

@@ -1884,7 +1881,7 @@ StandbyRecoverPreparedTransactions(bool overwriteOK)
18841881
buf = ProcessTwoPhaseBuffer(xid,
18851882
gxact->prepare_start_lsn,
18861883
gxact->ondisk, overwriteOK, true,
1887-
NULL, NULL);
1884+
false);
18881885
if (buf != NULL)
18891886
pfree(buf);
18901887
}
@@ -1924,7 +1921,7 @@ RecoverPreparedTransactions(void)
19241921
buf = ProcessTwoPhaseBuffer(xid,
19251922
gxact->prepare_start_lsn,
19261923
gxact->ondisk, false, false,
1927-
NULL, NULL);
1924+
false);
19281925
if (buf == NULL)
19291926
continue;
19301927

@@ -2012,20 +2009,16 @@ RecoverPreparedTransactions(void)
20122009
* If setParent is true, then use the overwriteOK parameter to set up
20132010
* subtransaction parent linkages.
20142011
*
2015-
* If result and maxsubxid are not NULL, fill them up with smallest
2016-
* running transaction id (lesser than ShmemVariableCache->nextXid)
2017-
* and largest subtransaction id for this transaction respectively.
2012+
* If setNextXid is true, set ShmemVariableCache->nextXid to the newest
2013+
* value scanned.
20182014
*/
20192015
static char *
20202016
ProcessTwoPhaseBuffer(TransactionId xid,
20212017
XLogRecPtr prepare_start_lsn,
20222018
bool fromdisk, bool overwriteOK,
2023-
bool setParent, TransactionId *result,
2024-
TransactionId *maxsubxid)
2019+
bool setParent, bool setNextXid)
20252020
{
20262021
TransactionId origNextXid = ShmemVariableCache->nextXid;
2027-
TransactionId res = InvalidTransactionId;
2028-
TransactionId maxsub = InvalidTransactionId;
20292022
TransactionId *subxids;
20302023
char *buf;
20312024
TwoPhaseFileHeader *hdr;
@@ -2034,11 +2027,6 @@ ProcessTwoPhaseBuffer(TransactionId xid,
20342027
if (!fromdisk)
20352028
Assert(prepare_start_lsn != InvalidXLogRecPtr);
20362029

2037-
if (result)
2038-
res = *result;
2039-
if (maxsubxid)
2040-
maxsub = *maxsubxid;
2041-
20422030
/* Already processed? */
20432031
if (TransactionIdDidCommit(xid) || TransactionIdDidAbort(xid))
20442032
{
@@ -2120,13 +2108,6 @@ ProcessTwoPhaseBuffer(TransactionId xid,
21202108
return NULL;
21212109
}
21222110

2123-
/*
2124-
* OK, we think this buffer is valid. Incorporate xid into the
2125-
* running-minimum result.
2126-
*/
2127-
if (TransactionIdPrecedes(xid, res))
2128-
res = xid;
2129-
21302111
/*
21312112
* Examine subtransaction XIDs ... they should all follow main
21322113
* XID, and they may force us to advance nextXid.
@@ -2139,17 +2120,31 @@ ProcessTwoPhaseBuffer(TransactionId xid,
21392120
TransactionId subxid = subxids[i];
21402121

21412122
Assert(TransactionIdFollows(subxid, xid));
2142-
if (TransactionIdFollowsOrEquals(subxid, maxsub))
2143-
maxsub = subxid;
2123+
2124+
/* update nextXid if needed */
2125+
if (setNextXid &&
2126+
TransactionIdFollowsOrEquals(subxid,
2127+
ShmemVariableCache->nextXid))
2128+
{
2129+
/*
2130+
* We don't expect anyone else to modify nextXid, hence we don't
2131+
* need to hold a lock while examining it. We still acquire the
2132+
* lock to modify it, though, so we recheck.
2133+
*/
2134+
LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
2135+
if (TransactionIdFollowsOrEquals(subxid,
2136+
ShmemVariableCache->nextXid))
2137+
{
2138+
ShmemVariableCache->nextXid = subxid;
2139+
TransactionIdAdvance(ShmemVariableCache->nextXid);
2140+
}
2141+
LWLockRelease(XidGenLock);
2142+
}
2143+
21442144
if (setParent)
21452145
SubTransSetParent(xid, subxid, overwriteOK);
21462146
}
21472147

2148-
if (result)
2149-
*result = res;
2150-
if (maxsubxid)
2151-
*maxsubxid = maxsub;
2152-
21532148
return buf;
21542149
}
21552150

0 commit comments

Comments
 (0)