From 7d2c63423d18f16fd5d4c21e49a4980f78cde69a Mon Sep 17 00:00:00 2001 From: Peter Geoghegan Date: Wed, 30 Mar 2022 18:59:41 -0700 Subject: [PATCH v14 3/4] PANIC on relfrozenxid from the future. This should be made into a WARNING later on. --- src/backend/commands/vacuum.c | 78 +++++++++++++++++++++++++++-------- 1 file changed, 60 insertions(+), 18 deletions(-) diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index deec4887b..40b6a723b 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -1340,7 +1340,11 @@ vac_update_relstats(Relation relation, Relation rd; HeapTuple ctup; Form_pg_class pgcform; - bool dirty; + bool dirty, + relfrozenxid_warn, + relminmxid_warn; + TransactionId oldrelfrozenxid; + MultiXactId oldrelminmxid; rd = table_open(RelationRelationId, RowExclusiveLock); @@ -1406,32 +1410,57 @@ vac_update_relstats(Relation relation, * This should match vac_update_datfrozenxid() concerning what we consider * to be "in the future". */ + relfrozenxid_warn = false; if (frozenxid_updated) *frozenxid_updated = false; - if (TransactionIdIsNormal(frozenxid) && - pgcform->relfrozenxid != frozenxid && - (TransactionIdPrecedes(pgcform->relfrozenxid, frozenxid) || - TransactionIdPrecedes(ReadNextTransactionId(), - pgcform->relfrozenxid))) + if (TransactionIdIsNormal(frozenxid) && pgcform->relfrozenxid != frozenxid) { - if (frozenxid_updated) - *frozenxid_updated = true; - pgcform->relfrozenxid = frozenxid; - dirty = true; + bool update = false; + + if (TransactionIdPrecedes(pgcform->relfrozenxid, frozenxid)) + update = true; + else if (TransactionIdPrecedes(ReadNextTransactionId(), + pgcform->relfrozenxid)) + { + relfrozenxid_warn = true; + oldrelfrozenxid = pgcform->relfrozenxid; + update = true; + } + + if (update) + { + if (frozenxid_updated) + *frozenxid_updated = true; + pgcform->relfrozenxid = frozenxid; + dirty = true; + } } /* Similarly for relminmxid */ + relminmxid_warn = false; if (minmulti_updated) *minmulti_updated = false; - if (MultiXactIdIsValid(minmulti) && - pgcform->relminmxid != minmulti && - (MultiXactIdPrecedes(pgcform->relminmxid, minmulti) || - MultiXactIdPrecedes(ReadNextMultiXactId(), pgcform->relminmxid))) + if (MultiXactIdIsValid(minmulti) && pgcform->relminmxid != minmulti) { - if (minmulti_updated) - *minmulti_updated = true; - pgcform->relminmxid = minmulti; - dirty = true; + bool update = false; + + if (MultiXactIdPrecedes(pgcform->relminmxid, minmulti)) + update = true; + else if (MultiXactIdPrecedes(ReadNextMultiXactId(), + pgcform->relminmxid)) + { + relminmxid_warn = true; + oldrelminmxid = pgcform->relminmxid; + update = true; + } + + if (update) + { + if (minmulti_updated) + *minmulti_updated = true; + pgcform->relminmxid = minmulti; + dirty = true; + } } /* If anything changed, write out the tuple. */ @@ -1439,6 +1468,19 @@ vac_update_relstats(Relation relation, heap_inplace_update(rd, ctup); table_close(rd, RowExclusiveLock); + + if (relfrozenxid_warn) + ereport(PANIC, + (errcode(ERRCODE_DATA_CORRUPTED), + errmsg_internal("overwrote invalid pg_class.relfrozenxid value %u with new value %u in table \"%s\"", + oldrelfrozenxid, frozenxid, + RelationGetRelationName(relation)))); + if (relminmxid_warn) + ereport(PANIC, + (errcode(ERRCODE_DATA_CORRUPTED), + errmsg_internal("overwrote invalid pg_class.relminmxid value %u with new value %u in table \"%s\"", + oldrelminmxid, minmulti, + RelationGetRelationName(relation)))); } -- 2.32.0