surely-dead-v1.patch
application/octet-stream
Filename: surely-dead-v1.patch
Type: application/octet-stream
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: unified
Series: patch v1
| File | + | − |
|---|---|---|
| src/backend/access/heap/heapam.c | 1 | 2 |
| src/backend/utils/time/tqual.c | 40 | 0 |
| src/include/utils/tqual.h | 2 | 0 |
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 3b7894e..3791f23 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -1609,8 +1609,7 @@ heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer,
* transactions.
*/
if (all_dead && *all_dead &&
- HeapTupleSatisfiesVacuum(heapTuple->t_data, RecentGlobalXmin,
- buffer) != HEAPTUPLE_DEAD)
+ !HeapTupleIsSurelyDead(heapTuple->t_data, RecentGlobalXmin))
*all_dead = false;
/*
diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c
index 31791a7..10571a5 100644
--- a/src/backend/utils/time/tqual.c
+++ b/src/backend/utils/time/tqual.c
@@ -1229,6 +1229,46 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin,
return HEAPTUPLE_DEAD;
}
+/*
+ * HeapTupleIsSurelyDead
+ *
+ * Determine whether a tuple is surely dead. We sometimes use this
+ * in lieu of HeapTupleSatisifesVacuum when the tuple has just been
+ * tested by HeapTupleSatisfiesMVCC and, therefore, any hint bits that
+ * can be set should already be set. We assume that if no hint bits
+ * either for xmin or xmax, the transaction is still running. This is
+ * therefore faster than HeapTupleSatisfiesVacuum, because we don't
+ * consult CLOG (and also because we don't need to give an exact answer,
+ * just whether or not the tuple is surely dead).
+ */
+bool
+HeapTupleIsSurelyDead(HeapTupleHeader tuple, TransactionId OldestXmin)
+{
+ /*
+ * If the inserting transaction is marked invalid, then it aborted,
+ * and the tuple is definitely dead. If it's marked neither committed
+ * nor invalid, then we assume it's still alive (since the presumption
+ * is that all relevant hint bits were just set moments ago).
+ */
+ if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
+ return (tuple->t_infomask & HEAP_XMIN_INVALID) != 0 ? true : false;
+
+ /*
+ * If the inserting transaction committed, but any deleting transaction
+ * aborted, the tuple is still alive. Likewise, if XMAX is a lock rather
+ * than a delete, the tuple is still alive.
+ */
+ if (tuple->t_infomask &
+ (HEAP_XMAX_INVALID | HEAP_IS_LOCKED | HEAP_XMAX_IS_MULTI))
+ return false;
+
+ /* If deleter isn't known to have committed, assume it's still running. */
+ if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
+ return false;
+
+ /* Deleter committed, so tuple is alive if the XID is old enough. */
+ return TransactionIdPrecedes(HeapTupleHeaderGetXmax(tuple), OldestXmin);
+}
/*
* XidInMVCCSnapshot
diff --git a/src/include/utils/tqual.h b/src/include/utils/tqual.h
index 0f8a7f8..3d8a480 100644
--- a/src/include/utils/tqual.h
+++ b/src/include/utils/tqual.h
@@ -83,6 +83,8 @@ extern HTSU_Result HeapTupleSatisfiesUpdate(HeapTupleHeader tuple,
CommandId curcid, Buffer buffer);
extern HTSV_Result HeapTupleSatisfiesVacuum(HeapTupleHeader tuple,
TransactionId OldestXmin, Buffer buffer);
+extern bool HeapTupleIsSurelyDead(HeapTupleHeader tuple,
+ TransactionId OldestXmin);
extern void HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer,
uint16 infomask, TransactionId xid);