fix_hang_15.patch

text/x-patch

Filename: fix_hang_15.patch
Type: text/x-patch
Part: 1
Message: Re: relfrozenxid may disagree with row XIDs after 1ccc1e05ae

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: format-patch
Series: patch v1
Subject: fix
File+
src/backend/access/heap/pruneheap.c 25 11
src/backend/access/heap/vacuumlazy.c 1 1
src/include/access/heapam.h 1 0
From eb5ed39ee00430755c45e4ed55ba1cde4c6fd79f Mon Sep 17 00:00:00 2001
From: Melanie Plageman <melanieplageman@gmail.com>
Date: Tue, 14 May 2024 10:35:14 -0400
Subject: [PATCH v1] fix

---
 src/backend/access/heap/pruneheap.c  | 36 +++++++++++++++++++---------
 src/backend/access/heap/vacuumlazy.c |  2 +-
 src/include/access/heapam.h          |  1 +
 3 files changed, 27 insertions(+), 12 deletions(-)

diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c
index 9f43bbe25f5..65d409e8b12 100644
--- a/src/backend/access/heap/pruneheap.c
+++ b/src/backend/access/heap/pruneheap.c
@@ -36,6 +36,12 @@ typedef struct
 	/* tuple visibility test, initialized for the relation */
 	GlobalVisState *vistest;
 
+	/*
+	 * Used only by vacuum. The oldest xmin at the beginning of vacuuming the
+	 * relation.
+	 */
+	TransactionId oldest_xmin;
+
 	/*
 	 * Thresholds set by TransactionIdLimitedForOldSnapshots() if they have
 	 * been computed (done on demand, and only if
@@ -206,8 +212,8 @@ heap_page_prune_opt(Relation relation, Buffer buffer)
 			int			ndeleted,
 						nnewlpdead;
 
-			ndeleted = heap_page_prune(relation, buffer, vistest, limited_xmin,
-									   limited_ts, &nnewlpdead, NULL);
+			ndeleted = heap_page_prune(relation, buffer, vistest, InvalidTransactionId,
+					limited_xmin, limited_ts, &nnewlpdead, NULL);
 
 			/*
 			 * Report the number of tuples reclaimed to pgstats.  This is
@@ -248,11 +254,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 is used to distinguish whether tuples are DEAD or RECENTLY_DEAD (see
+ * heap_prune_satisfies_vacuum and HeapTupleSatisfiesVacuum).
+ *
+ * oldest_xmin is only set to a valid TransactionId by vacuum. It is the oldest
+ * removable TransactionId at the beginning of vacuuming the relation.
+ *
+ * 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.
@@ -265,6 +274,7 @@ heap_page_prune_opt(Relation relation, Buffer buffer)
 int
 heap_page_prune(Relation relation, Buffer buffer,
 				GlobalVisState *vistest,
+				TransactionId oldest_xmin,
 				TransactionId old_snap_xmin,
 				TimestampTz old_snap_ts,
 				int *nnewlpdead,
@@ -292,6 +302,7 @@ heap_page_prune(Relation relation, Buffer buffer,
 	prstate.new_prune_xid = InvalidTransactionId;
 	prstate.rel = relation;
 	prstate.vistest = vistest;
+	prstate.oldest_xmin = oldest_xmin;
 	prstate.old_snap_xmin = old_snap_xmin;
 	prstate.old_snap_ts = old_snap_ts;
 	prstate.old_snap_used = false;
@@ -520,11 +531,14 @@ 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.
+	 * First check if oldest_xmin or GlobalVisTestIsRemovableXid() is
+	 * sufficient to find the row dead. If not, and old_snapshot_threshold is
+	 * enabled, try to use the lowered horizon.
 	 */
-	if (GlobalVisTestIsRemovableXid(prstate->vistest, dead_after))
+	if (TransactionIdIsValid(prstate->oldest_xmin) &&
+			NormalTransactionIdPrecedes(dead_after, prstate->oldest_xmin))
+			res = HEAPTUPLE_DEAD;
+	else if (GlobalVisTestIsRemovableXid(prstate->vistest, dead_after))
 		res = HEAPTUPLE_DEAD;
 	else if (OldSnapshotThresholdActive())
 	{
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index 2e61e2f20b4..a027458cf69 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -1585,7 +1585,7 @@ retry:
 	 * lpdead_items's final value can be thought of as the number of tuples
 	 * that were deleted from indexes.
 	 */
-	tuples_deleted = heap_page_prune(rel, buf, vacrel->vistest,
+	tuples_deleted = heap_page_prune(rel, buf, vacrel->vistest, vacrel->OldestXmin,
 									 InvalidTransactionId, 0, &nnewlpdead,
 									 &vacrel->offnum);
 
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
index abf62d9df79..e39fa14c1b2 100644
--- a/src/include/access/heapam.h
+++ b/src/include/access/heapam.h
@@ -186,6 +186,7 @@ struct GlobalVisState;
 extern void heap_page_prune_opt(Relation relation, Buffer buffer);
 extern int	heap_page_prune(Relation relation, Buffer buffer,
 							struct GlobalVisState *vistest,
+							TransactionId oldest_xmin,
 							TransactionId old_snap_xmin,
 							TimestampTz old_snap_ts_ts,
 							int *nnewlpdead,
-- 
2.34.1