Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit bf70bf4

Browse files
Derive oldestActiveXid at correct time for Hot Standby.
There was a timing window between when oldestActiveXid was derived and when it should have been derived that only shows itself under heavy load. Move code around to ensure correct timing of derivation. No change to StartupSUBTRANS() code, which is where this failed. Bug report by Chris Redekop
1 parent 93b915b commit bf70bf4

File tree

5 files changed

+71
-6
lines changed

5 files changed

+71
-6
lines changed

src/backend/access/transam/xlog.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7598,6 +7598,16 @@ CreateCheckPoint(int flags)
75987598
MemSet(&checkPoint, 0, sizeof(checkPoint));
75997599
checkPoint.time = (pg_time_t) time(NULL);
76007600

7601+
/*
7602+
* For Hot Standby, derive the oldestActiveXid before we fix the redo pointer.
7603+
* This allows us to begin accumulating changes to assemble our starting
7604+
* snapshot of locks and transactions.
7605+
*/
7606+
if (!shutdown && XLogStandbyInfoActive())
7607+
checkPoint.oldestActiveXid = GetOldestActiveTransactionId();
7608+
else
7609+
checkPoint.oldestActiveXid = InvalidTransactionId;
7610+
76017611
/*
76027612
* We must hold WALInsertLock while examining insert state to determine
76037613
* the checkpoint REDO pointer.
@@ -7784,9 +7794,7 @@ CreateCheckPoint(int flags)
77847794
* Update checkPoint.nextXid since we have a later value
77857795
*/
77867796
if (!shutdown && XLogStandbyInfoActive())
7787-
LogStandbySnapshot(&checkPoint.oldestActiveXid, &checkPoint.nextXid);
7788-
else
7789-
checkPoint.oldestActiveXid = InvalidTransactionId;
7797+
LogStandbySnapshot(&checkPoint.nextXid);
77907798

77917799
START_CRIT_SECTION();
77927800

src/backend/storage/ipc/procarray.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1528,6 +1528,63 @@ GetRunningTransactionData(void)
15281528
return CurrentRunningXacts;
15291529
}
15301530

1531+
/*
1532+
* GetOldestActiveTransactionId()
1533+
*
1534+
* Similar to GetSnapshotData but returns just oldestActiveXid. We include
1535+
* all PGPROCs with an assigned TransactionId, even VACUUM processes.
1536+
* We look at all databases, though there is no need to include WALSender
1537+
* since this has no effect on hot standby conflicts.
1538+
*
1539+
* This is never executed during recovery so there is no need to look at
1540+
* KnownAssignedXids.
1541+
*
1542+
* We don't worry about updating other counters, we want to keep this as
1543+
* simple as possible and leave GetSnapshotData() as the primary code for
1544+
* that bookkeeping.
1545+
*/
1546+
TransactionId
1547+
GetOldestActiveTransactionId(void)
1548+
{
1549+
ProcArrayStruct *arrayP = procArray;
1550+
TransactionId oldestRunningXid;
1551+
int index;
1552+
1553+
Assert(!RecoveryInProgress());
1554+
1555+
LWLockAcquire(ProcArrayLock, LW_SHARED);
1556+
1557+
oldestRunningXid = ShmemVariableCache->nextXid;
1558+
1559+
/*
1560+
* Spin over procArray collecting all xids and subxids.
1561+
*/
1562+
for (index = 0; index < arrayP->numProcs; index++)
1563+
{
1564+
volatile PGPROC *proc = arrayP->procs[index];
1565+
TransactionId xid;
1566+
1567+
/* Fetch xid just once - see GetNewTransactionId */
1568+
xid = proc->xid;
1569+
1570+
if (!TransactionIdIsNormal(xid))
1571+
continue;
1572+
1573+
if (TransactionIdPrecedes(xid, oldestRunningXid))
1574+
oldestRunningXid = xid;
1575+
1576+
/*
1577+
* Top-level XID of a transaction is always less than any of its
1578+
* subxids, so we don't need to check if any of the subxids are
1579+
* smaller than oldestRunningXid
1580+
*/
1581+
}
1582+
1583+
LWLockRelease(ProcArrayLock);
1584+
1585+
return oldestRunningXid;
1586+
}
1587+
15311588
/*
15321589
* GetTransactionsInCommit -- Get the XIDs of transactions that are committing
15331590
*

src/backend/storage/ipc/standby.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -814,7 +814,7 @@ standby_desc(StringInfo buf, uint8 xl_info, char *rec)
814814
* making WAL entries.
815815
*/
816816
void
817-
LogStandbySnapshot(TransactionId *oldestActiveXid, TransactionId *nextXid)
817+
LogStandbySnapshot(TransactionId *nextXid)
818818
{
819819
RunningTransactions running;
820820
xl_standby_lock *locks;
@@ -844,7 +844,6 @@ LogStandbySnapshot(TransactionId *oldestActiveXid, TransactionId *nextXid)
844844
/* GetRunningTransactionData() acquired XidGenLock, we must release it */
845845
LWLockRelease(XidGenLock);
846846

847-
*oldestActiveXid = running->oldestRunningXid;
848847
*nextXid = running->nextXid;
849848
}
850849

src/include/storage/procarray.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ extern Snapshot GetSnapshotData(Snapshot snapshot);
4646
extern bool TransactionIdIsInProgress(TransactionId xid);
4747
extern bool TransactionIdIsActive(TransactionId xid);
4848
extern TransactionId GetOldestXmin(bool allDbs, bool ignoreVacuum);
49+
extern TransactionId GetOldestActiveTransactionId(void);
4950

5051
extern int GetTransactionsInCommit(TransactionId **xids_p);
5152
extern bool HaveTransactionsInCommit(TransactionId *xids, int nxids);

src/include/storage/standby.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,6 @@ typedef RunningTransactionsData *RunningTransactions;
111111
extern void LogAccessExclusiveLock(Oid dbOid, Oid relOid);
112112
extern void LogAccessExclusiveLockPrepare(void);
113113

114-
extern void LogStandbySnapshot(TransactionId *oldestActiveXid, TransactionId *nextXid);
114+
extern void LogStandbySnapshot(TransactionId *nextXid);
115115

116116
#endif /* STANDBY_H */

0 commit comments

Comments
 (0)