Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit74fc838

Browse files
committed
Fix race between GetNewTransactionId and GetOldestActiveTransactionId.
The race condition goes like this:1. GetNewTransactionId advances nextXid e.g. from 100 to 1012. GetOldestActiveTransactionId reads the new nextXid, 1013. GetOldestActiveTransactionId loops through the proc array. There are no active XIDs there, so it returns 101 as the oldest active XID.4. GetNewTransactionid stores XID 100 to MyPgXact->xidSo, GetOldestActiveTransactionId returned XID 101, even though 100 onlyjust started and is surely still running.This would be hard to hit in practice, and even harder to spot any illeffect if it happens. GetOldestActiveTransactionId is only used whencreating a checkpoint in a master server, and the race condition can onlyhappen on an online checkpoint, as there are no backends running during ashutdown checkpoint. The oldestActiveXid value of an online checkpoint isonly used when starting up a hot standby server, to determine the startingpoint where pg_subtrans is initialized from. For the race condition tohappen, there must be no other XIDs in the proc array that would hold backthe oldest-active XID value, which means that the missed XID must be a toptransaction's XID. However, pg_subtrans is not used for top XIDs, so Ibelieve an off-by-one error is in fact inconsequential. Nevertheless, let'sfix it, as it's clearly wrong and the fix is simple.This has been wrong ever since hot standby was introduced, so backport toall supported versions.Discussion:https://www.postgresql.org/message-id/e7258662-82b6-7a45-56d4-99b337a32bf7@iki.fi
1 parentbc2d716 commit74fc838

File tree

1 file changed

+8
-8
lines changed

1 file changed

+8
-8
lines changed

‎src/backend/storage/ipc/procarray.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2096,20 +2096,21 @@ GetOldestActiveTransactionId(void)
20962096

20972097
Assert(!RecoveryInProgress());
20982098

2099-
LWLockAcquire(ProcArrayLock,LW_SHARED);
2100-
21012099
/*
2102-
*It's okay to read nextXid without acquiring XidGenLock because (1) we
2103-
* assume TransactionIds can be read atomically and (2) we don't care if
2104-
*we get a slightly stale value. It can't be very stale anyway, because
2105-
*the LWLockAcquire above will have done any necessary memory
2106-
*interlocking.
2100+
*Read nextXid, as the upper bound of what's still active.
2101+
*
2102+
*Reading a TransactionId is atomic, but we must grab the lock to make
2103+
*sure that all XIDs < nextXid are already present in the proc array (or
2104+
*have already completed), when we spin over it.
21072105
*/
2106+
LWLockAcquire(XidGenLock,LW_SHARED);
21082107
oldestRunningXid=ShmemVariableCache->nextXid;
2108+
LWLockRelease(XidGenLock);
21092109

21102110
/*
21112111
* Spin over procArray collecting all xids and subxids.
21122112
*/
2113+
LWLockAcquire(ProcArrayLock,LW_SHARED);
21132114
for (index=0;index<arrayP->numProcs;index++)
21142115
{
21152116
intpgprocno=arrayP->pgprocnos[index];
@@ -2131,7 +2132,6 @@ GetOldestActiveTransactionId(void)
21312132
* smaller than oldestRunningXid
21322133
*/
21332134
}
2134-
21352135
LWLockRelease(ProcArrayLock);
21362136

21372137
returnoldestRunningXid;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp