all_visible_cheap_check.v1.patch

application/octet-stream

Filename: all_visible_cheap_check.v1.patch
Type: application/octet-stream
Part: 0
Message: Re: Do we need so many hint bits?

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 1
src/backend/utils/time/tqual.c 58 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 64aecf2..b83b10e 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -281,7 +281,7 @@ heapgetpage(HeapScanDesc scan, BlockNumber page)
 			ItemPointerSet(&(loctup.t_self), page, lineoff);
 
 			if (all_visible)
-				valid = true;
+				valid = HeapTupleSatisfiesAllVisible(loctup.t_data, snapshot, buffer);
 			else
 				valid = HeapTupleSatisfiesVisibility(&loctup, snapshot, buffer);
 
diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c
index b531db5..707184e 100644
--- a/src/backend/utils/time/tqual.c
+++ b/src/backend/utils/time/tqual.c
@@ -1044,6 +1044,64 @@ HeapTupleSatisfiesMVCC(HeapTupleHeader tuple, Snapshot snapshot,
 	return false;
 }
 
+/*
+ * When we know that the page this tuple is on *was* marked all visible
+ * we can skip all clog lookups altogether and just rely on MVCC rules.
+ * Clog lookups might reveal come committed transactions but this is
+ * relatively unlikely since they would need to win the race against
+ * our recent test of the VM. And even if they did, our scan can't see
+ * them anyway, so we just avoid all that work completely.
+ */
+bool
+HeapTupleSatisfiesAllVisible(HeapTupleHeader tuple, Snapshot snapshot,
+					   Buffer buffer)
+{
+	/*
+	 * At the start we know all visible inserting transactions are committed -
+	 * - so we only have to check visibility against our snapshot.
+	 */
+	if (XidInMVCCSnapshot(HeapTupleHeaderGetXmin(tuple), snapshot))
+		return false;			/* treat as still in progress */
+
+	if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid or aborted */
+		return true;
+
+	if (tuple->t_infomask & HEAP_IS_LOCKED)
+		return true;
+
+	if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
+	{
+		/* MultiXacts are currently only allowed to lock tuples */
+		Assert(tuple->t_infomask & HEAP_IS_LOCKED);
+		return true;
+	}
+
+	/*
+	 * Need to be careful here to ensure we don't insert rows
+	 * ourselves during the scan. Test is cheap when we have no xid.
+	 */
+	if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))
+	{
+		if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid)
+			return false;	/* inserted after scan started */
+		else
+			return true;	/* inserted before scan started */
+	}
+
+	/*
+	 * Similar tests for our own deletes. Test is very cheap when xmax
+	 * is invalid and also cheap when we don't have an xid ourselves.
+	 */
+	if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
+	{
+		if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
+			return true;	/* deleted after scan started */
+		else
+			return false;	/* deleted before scan started */
+	}
+
+	return true;
+}
 
 /*
  * HeapTupleSatisfiesVacuum
diff --git a/src/include/utils/tqual.h b/src/include/utils/tqual.h
index ff74f86..342c861 100644
--- a/src/include/utils/tqual.h
+++ b/src/include/utils/tqual.h
@@ -67,6 +67,8 @@ typedef enum
 /* These are the "satisfies" test routines for the various snapshot types */
 extern bool HeapTupleSatisfiesMVCC(HeapTupleHeader tuple,
 					   Snapshot snapshot, Buffer buffer);
+extern bool HeapTupleSatisfiesAllVisible(HeapTupleHeader tuple,
+					   Snapshot snapshot, Buffer buffer);
 extern bool HeapTupleSatisfiesNow(HeapTupleHeader tuple,
 					  Snapshot snapshot, Buffer buffer);
 extern bool HeapTupleSatisfiesSelf(HeapTupleHeader tuple,