diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index d088dc1..8b8b97f 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -765,7 +765,7 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex, bool verbose, HeapScanDesc heapScan; bool use_wal; bool is_system_catalog; - TransactionId OldestXmin; + TransactionId OldestXmin = InvalidTransactionId; TransactionId FreezeXid; MultiXactId MultiXactCutoff; RewriteState rwstate; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index d90cb9a..d745127 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -75,7 +75,7 @@ static void vac_truncate_clog(TransactionId frozenXID, TransactionId lastSaneFrozenXid, MultiXactId lastSaneMinMulti); static bool vacuum_rel(Oid relid, RangeVar *relation, int options, - VacuumParams *params); + VacuumParams *params, TransactionId oldestXmin); /* * Primary entry point for manual VACUUM and ANALYZE commands @@ -337,7 +337,8 @@ vacuum(int options, List *relations, VacuumParams *params, if (options & VACOPT_VACUUM) { - if (!vacuum_rel(vrel->oid, vrel->relation, options, params)) + if (!vacuum_rel(vrel->oid, vrel->relation, options, params, + InvalidTransactionId)) continue; } @@ -618,8 +619,9 @@ vacuum_set_xid_limits(Relation rel, * working on a particular table at any time, and that each vacuum is * always an independent transaction. */ - *oldestXmin = - TransactionIdLimitedForOldSnapshots(GetOldestXmin(rel, PROCARRAY_FLAGS_VACUUM), rel); + if (!TransactionIdIsValid(*oldestXmin)) + *oldestXmin = + TransactionIdLimitedForOldSnapshots(GetOldestXmin(rel, PROCARRAY_FLAGS_VACUUM), rel); Assert(TransactionIdIsNormal(*oldestXmin)); @@ -1298,7 +1300,8 @@ vac_truncate_clog(TransactionId frozenXID, * At entry and exit, we are not inside a transaction. */ static bool -vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params) +vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params, + TransactionId oldestXmin) { LOCKMODE lmode; Relation onerel; @@ -1530,6 +1533,19 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params) toast_relid = InvalidOid; /* + * Use same OldestXmin for heap and toast table, otherwise, the heap can + * have RECENTLY_DEAD row that contains toast pointers whose toast rows + * have already been vacuumed away. This is because OldestXmin can move + * backward on repeated calls. See GetOldestXmin. + */ + if (OidIsValid(toast_relid)) + { + if (!TransactionIdIsValid(oldestXmin)) + oldestXmin = + TransactionIdLimitedForOldSnapshots(GetOldestXmin(onerel, PROCARRAY_FLAGS_VACUUM), onerel); + } + + /* * Switch to the table owner's userid, so that any index functions are run * as that user. Also lock down security-restricted operations and * arrange to make GUC variable changes local to this command. (This is @@ -1554,7 +1570,7 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params) (options & VACOPT_VERBOSE) != 0); } else - lazy_vacuum_rel(onerel, options, params, vac_strategy); + lazy_vacuum_rel(onerel, options, params, vac_strategy, oldestXmin); /* Roll back any GUC changes executed by index functions */ AtEOXact_GUC(false, save_nestlevel); @@ -1580,7 +1596,7 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params) * totally unimportant for toast relations. */ if (toast_relid != InvalidOid) - vacuum_rel(toast_relid, NULL, options, params); + vacuum_rel(toast_relid, NULL, options, params, oldestXmin); /* * Now release the session-level lock on the master table. diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c index 5649a70..9331089 100644 --- a/src/backend/commands/vacuumlazy.c +++ b/src/backend/commands/vacuumlazy.c @@ -188,7 +188,7 @@ static bool heap_page_is_all_visible(Relation rel, Buffer buf, */ void lazy_vacuum_rel(Relation onerel, int options, VacuumParams *params, - BufferAccessStrategy bstrategy) + BufferAccessStrategy bstrategy, TransactionId oldestXmin) { LVRelStats *vacrelstats; Relation *Irel; @@ -233,8 +233,9 @@ lazy_vacuum_rel(Relation onerel, int options, VacuumParams *params, params->freeze_table_age, params->multixact_freeze_min_age, params->multixact_freeze_table_age, - &OldestXmin, &FreezeLimit, &xidFullScanLimit, + &oldestXmin, &FreezeLimit, &xidFullScanLimit, &MultiXactCutoff, &mxactFullScanLimit); + OldestXmin = oldestXmin; /* * We request an aggressive scan if the table's frozen Xid is now older diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index 85d472f..38a3c60 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -188,7 +188,8 @@ extern void vacuum_delay_point(void); /* in commands/vacuumlazy.c */ extern void lazy_vacuum_rel(Relation onerel, int options, - VacuumParams *params, BufferAccessStrategy bstrategy); + VacuumParams *params, BufferAccessStrategy bstrategy, + TransactionId oldestXmin); /* in commands/analyze.c */ extern void analyze_rel(Oid relid, RangeVar *relation, int options,