mirror of
https://github.com/postgres/postgres.git
synced 2025-10-19 15:49:24 +03:00
Prevent concurrent SimpleLruTruncate() for any given SLRU.
The SimpleLruTruncate() header comment states the new coding rule. To achieve this, add locktype "frozenid" and two LWLocks. This closes a rare opportunity for data loss, which manifested as "apparent wraparound" or "could not access status of transaction" errors. Data loss is more likely in pg_multixact, due to released branches' thin margin between multiStopLimit and multiWrapLimit. If a user's physical replication primary logged ": apparent wraparound" messages, the user should rebuild standbys of that primary regardless of symptoms. At less risk is a cluster having emitted "not accepting commands" errors or "must be vacuumed" warnings at some point. One can test a cluster for this data loss by running VACUUM FREEZE in every database. Back-patch to 9.5 (all supported versions). Discussion: https://postgr.es/m/20190218073103.GA1434723@rfd.leadboat.com
This commit is contained in:
@@ -1017,6 +1017,14 @@ vac_update_datfrozenxid(void)
|
||||
bool bogus = false;
|
||||
bool dirty = false;
|
||||
|
||||
/*
|
||||
* Restrict this task to one backend per database. This avoids race
|
||||
* conditions that would move datfrozenxid or datminmxid backward. It
|
||||
* avoids calling vac_truncate_clog() with a datfrozenxid preceding a
|
||||
* datfrozenxid passed to an earlier vac_truncate_clog() call.
|
||||
*/
|
||||
LockDatabaseFrozenIds(ExclusiveLock);
|
||||
|
||||
/*
|
||||
* Initialize the "min" calculation with GetOldestXmin, which is a
|
||||
* reasonable approximation to the minimum relfrozenxid for not-yet-
|
||||
@@ -1181,6 +1189,9 @@ vac_truncate_clog(TransactionId frozenXID,
|
||||
bool bogus = false;
|
||||
bool frozenAlreadyWrapped = false;
|
||||
|
||||
/* Restrict task to one backend per cluster; see SimpleLruTruncate(). */
|
||||
LWLockAcquire(WrapLimitsVacuumLock, LW_EXCLUSIVE);
|
||||
|
||||
/* init oldest datoids to sync with my frozenXID/minMulti values */
|
||||
oldestxid_datoid = MyDatabaseId;
|
||||
minmulti_datoid = MyDatabaseId;
|
||||
@@ -1290,6 +1301,8 @@ vac_truncate_clog(TransactionId frozenXID,
|
||||
*/
|
||||
SetTransactionIdLimit(frozenXID, oldestxid_datoid);
|
||||
SetMultiXactIdLimit(minMulti, minmulti_datoid, false);
|
||||
|
||||
LWLockRelease(WrapLimitsVacuumLock);
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user