Re: BUG: Postgres 14 + vacuum_defer_cleanup_age + FOR UPDATE + UPDATE
Andres Freund <andres@anarazel.de>
From: Andres Freund <andres@anarazel.de>
To: Michail Nikolaev <michail.nikolaev@gmail.com>, Thomas Munro <thomas.munro@gmail.com>, Peter Geoghegan <pg@bowt.ie>, Matthias van de Meent <boekewurm+postgres@gmail.com>
Cc: PostgreSQL Hackers <pgsql-hackers@postgresql.org>
Date: 2023-01-08T03:09:56Z
Lists: pgsql-hackers
Hi, On 2023-01-07 16:29:23 -0800, Andres Freund wrote: > It's probably not too hard to fix specifically in this one place - we could > just clamp vacuum_defer_cleanup_age to be smaller than latest_completed, but > it strikes me as as a somewhat larger issue for the 64it xid infrastructure. I > suspect this might not be the only place running into problems with such > "before the universe" xids. I haven't found other problematic places in HEAD, but did end up find a less serious version of this bug in < 14: GetFullRecentGlobalXmin(). I did verify that with vacuum_defer_cleanup_age set GetFullRecentGlobalXmin() returns values that look likely to cause problems. Its "just" used in gist luckily. It's hard to find places that do this kind of arithmetic, we traditionally haven't had a helper for it. So it's open-coded in various ways. xidStopLimit = xidWrapLimit - 3000000; if (xidStopLimit < FirstNormalTransactionId) xidStopLimit -= FirstNormalTransactionId; and oddly: xidVacLimit = oldest_datfrozenxid + autovacuum_freeze_max_age; if (xidVacLimit < FirstNormalTransactionId) xidVacLimit += FirstNormalTransactionId; or (in < 14): RecentGlobalXmin = globalxmin - vacuum_defer_cleanup_age; if (!TransactionIdIsNormal(RecentGlobalXmin)) RecentGlobalXmin = FirstNormalTransactionId; The currently existing places I found, other than the ones in procarray.c, luckily don't seem to convert the xids to 64bit xids. > For a bit I was thinking that we should introduce the notion that a > FullTransactionId can be from the past. Specifically that when the upper 32bit > are all set, we treat the lower 32bit as a value from before xid 0 using the > normal 32bit xid arithmetic. But it sucks to add overhead for that > everywhere. > > It might be a bit more palatable to designate one individual value, > e.g. 2^32-1<<32, as a "before xid 0" indicator - it doesn't matter how far > before the start of the universe an xid point to... On IM Thomas suggested we could reserve the 2^32-1 epoch for invalid values. I hacked up a patch that converts various fxid functions to inline functions with such assertions, and it indeed quickly catches the problem this thread reported, close to the source of the use. One issue with that is is that it'd reduce what can be input for the xid8 type. But it's hard to believe that'd be a real issue? It's quite unfortunate that we don't have a test for vacuum_defer_cleanup_age yet :(. Greetings, Andres Freund
Commits
-
Fix incorrect TAP test ordering
- 92155e15d3cf 16.0 landed
-
pg_amcheck: Minor test speedups
- a4f23f9b3cdd 16.0 landed
-
amcheck: Fix FullTransactionIdFromXidAndCtx() for xids before epoch 0
- b3a83055c235 14.8 landed
- e8a9750d03d7 15.3 landed
- 4f5d461e048b 16.0 landed
-
amcheck: Fix ordering bug in update_cached_xid_range()
- a42f515d6b45 14.8 landed
- 6d9588108a56 15.3 landed
- 16327240da29 16.0 landed
-
Fix corruption due to vacuum_defer_cleanup_age underflowing 64bit xids
- be504a3e974d 16.0 landed
- 3c92f7e9d851 12.15 landed
- e6d77f22c7a8 13.11 landed
- 324281fd5b1b 14.8 landed
- 391f08fd6804 15.3 landed
-
Add hardening to catch invalid TIDs in indexes.
- e7428a99a13f 15.0 cited
-
Use full 64-bit XID for checking if a deleted GiST page is old enough.
- 6655a7299d83 13.0 cited
-
Avoid early reuse of btree pages, causing incorrect query results.
- d3abbbebe52e 9.2.0 cited