{
Relation rel;
- /* tuple visibility test, initialized for the relation */
+ /* State used to test tuple visibility; Initialized for the relation */
+ TransactionId oldest_xmin;
GlobalVisState *vistest;
/*
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);
/*
* 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.
*/
int
heap_page_prune(Relation relation, Buffer buffer,
+ TransactionId oldest_xmin,
GlobalVisState *vistest,
TransactionId old_snap_xmin,
TimestampTz old_snap_ts,
*/
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;
}
/*
- * 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))