surely-dead-v1.patch

application/octet-stream

Filename: surely-dead-v1.patch
Type: application/octet-stream
Part: 0
Message: clog double-dip in heap_hot_search_buffer

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);