diff options
Diffstat (limited to 'src/backend/access/heap/pruneheap.c')
-rw-r--r-- | src/backend/access/heap/pruneheap.c | 49 |
1 files changed, 37 insertions, 12 deletions
diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c index 9f43bbe25f5..72ce130346c 100644 --- a/src/backend/access/heap/pruneheap.c +++ b/src/backend/access/heap/pruneheap.c @@ -33,7 +33,8 @@ typedef struct { Relation rel; - /* tuple visibility test, initialized for the relation */ + /* State used to test tuple visibility; Initialized for the relation */ + TransactionId oldest_xmin; GlobalVisState *vistest; /* @@ -206,7 +207,8 @@ heap_page_prune_opt(Relation relation, Buffer buffer) int ndeleted, nnewlpdead; - ndeleted = heap_page_prune(relation, buffer, vistest, limited_xmin, + ndeleted = heap_page_prune(relation, buffer, InvalidTransactionId, + vistest, limited_xmin, limited_ts, &nnewlpdead, NULL); /* @@ -248,11 +250,14 @@ heap_page_prune_opt(Relation relation, Buffer buffer) * also need to account for a reduction in the length of the line pointer * array following array truncation by us. * - * vistest is used to distinguish whether tuples are DEAD or RECENTLY_DEAD - * (see heap_prune_satisfies_vacuum and - * HeapTupleSatisfiesVacuum). old_snap_xmin / old_snap_ts need to - * either have been set by TransactionIdLimitedForOldSnapshots, or - * InvalidTransactionId/0 respectively. + * vistest and oldest_xmin are used to distinguish whether tuples are DEAD or + * RECENTLY_DEAD (see heap_prune_satisfies_vacuum and + * HeapTupleSatisfiesVacuum). If oldest_xmin is provided by the caller, it is + * used before consulting GlobalVisState. + * + * old_snap_xmin / old_snap_ts need to either have been set by + * TransactionIdLimitedForOldSnapshots, or InvalidTransactionId/0 + * respectively. * * Sets *nnewlpdead for caller, indicating the number of items that were * newly set LP_DEAD during prune operation. @@ -264,6 +269,7 @@ heap_page_prune_opt(Relation relation, Buffer buffer) */ int heap_page_prune(Relation relation, Buffer buffer, + TransactionId oldest_xmin, GlobalVisState *vistest, TransactionId old_snap_xmin, TimestampTz old_snap_ts, @@ -291,6 +297,7 @@ heap_page_prune(Relation relation, Buffer buffer, */ prstate.new_prune_xid = InvalidTransactionId; prstate.rel = relation; + prstate.oldest_xmin = oldest_xmin; prstate.vistest = vistest; prstate.old_snap_xmin = old_snap_xmin; prstate.old_snap_ts = old_snap_ts; @@ -520,13 +527,31 @@ heap_prune_satisfies_vacuum(PruneState *prstate, HeapTuple tup, Buffer buffer) } /* - * First check if GlobalVisTestIsRemovableXid() is sufficient to find the - * row dead. If not, and old_snapshot_threshold is enabled, try to use the - * lowered horizon. + * For VACUUM, we must be sure to prune tuples with xmax older than + * oldest_xmin -- a visibility cutoff determined at the beginning of + * vacuuming the relation. oldest_xmin is used for freezing determination + * and we cannot freeze dead tuples' xmaxes. + */ + if (TransactionIdIsValid(prstate->oldest_xmin) && + NormalTransactionIdPrecedes(dead_after, prstate->oldest_xmin)) + return HEAPTUPLE_DEAD; + + /* + * Determine whether or not the tuple is considered dead when compared + * with the provided GlobalVisState. On-access pruning does not provide + * oldest_xmin. And for vacuum, even if the tuple's xmax is not older than + * oldest_xmin, GlobalVisTestIsRemovableXid() could find the row dead if + * the GlobalVisState has been updated since the beginning of vacuuming + * the relation. */ if (GlobalVisTestIsRemovableXid(prstate->vistest, dead_after)) - res = HEAPTUPLE_DEAD; - else if (OldSnapshotThresholdActive()) + return HEAPTUPLE_DEAD; + + /* + * If GlobalVisTestIsRemovableXid() is not sufficient to find the row dead + * and old_snapshot_threshold is enabled, try to use the lowered horizon. + */ + if (OldSnapshotThresholdActive()) { /* haven't determined limited horizon yet, requests */ if (!TransactionIdIsValid(prstate->old_snap_xmin)) |