v1-0001-Fix-vacuum-hang.patch
text/x-patch
Filename: v1-0001-Fix-vacuum-hang.patch
Type: text/x-patch
Part: 0
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-0001
Subject: Fix vacuum hang
| File | + | − |
|---|---|---|
| src/backend/access/heap/pruneheap.c | 24 | 9 |
| src/backend/access/heap/vacuumlazy.c | 1 | 1 |
| src/include/access/heapam.h | 1 | 0 |
From 33ec54d05441183ba908a728186b2a6751bc4cf5 Mon Sep 17 00:00:00 2001
From: Melanie Plageman <melanieplageman@gmail.com>
Date: Mon, 13 May 2024 10:27:50 -0400
Subject: [PATCH v1] Fix vacuum hang
---
src/backend/access/heap/pruneheap.c | 33 ++++++++++++++++++++--------
src/backend/access/heap/vacuumlazy.c | 2 +-
src/include/access/heapam.h | 1 +
3 files changed, 26 insertions(+), 10 deletions(-)
diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c
index f7f8056d631..0356391c5db 100644
--- a/src/backend/access/heap/pruneheap.c
+++ b/src/backend/access/heap/pruneheap.c
@@ -35,6 +35,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
@@ -203,6 +209,7 @@ heap_page_prune_opt(Relation relation, Buffer buffer)
{
/* OK to prune */
(void) heap_page_prune(relation, buffer, vistest,
+ InvalidTransactionId,
limited_xmin, limited_ts,
true, NULL);
}
@@ -218,11 +225,14 @@ heap_page_prune_opt(Relation relation, Buffer buffer)
*
* Caller must have pin and buffer cleanup lock on the page.
*
- * 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.
*
* If report_stats is true then we send the number of reclaimed heap-only
* tuples to pgstats. (This must be false during vacuum, since vacuum will
@@ -237,6 +247,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,
bool report_stats,
@@ -263,6 +274,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;
@@ -512,11 +524,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 8aab6e324e0..31fdc8e6cd9 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -1738,7 +1738,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, vistest,
+ tuples_deleted = heap_page_prune(rel, buf, vistest, vacrel->OldestXmin,
InvalidTransactionId, 0, false,
&vacrel->offnum);
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
index 4f1dff9ca1b..780b30fe74c 100644
--- a/src/include/access/heapam.h
+++ b/src/include/access/heapam.h
@@ -187,6 +187,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,
bool report_stats,
--
2.34.1