0003-Defend-against-heapallindexed-using-transaction-snap.patch

text/x-patch

Filename: 0003-Defend-against-heapallindexed-using-transaction-snap.patch
Type: text/x-patch
Part: 0
Message: Re: [HACKERS] A design for amcheck heapam verification

Patch

Format: format-patch
Series: patch 0003
Subject: Defend against heapallindexed using transaction snapshot.
File+
contrib/amcheck/verify_nbtree.c 25 0
From 080e3b512a0ad80147cd8d6aaba02e9df5b92daf Mon Sep 17 00:00:00 2001
From: Peter Geoghegan <pg@bowt.ie>
Date: Tue, 27 Mar 2018 13:33:33 -0700
Subject: [PATCH 3/3] Defend against heapallindexed using transaction snapshot.

---
 contrib/amcheck/verify_nbtree.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/contrib/amcheck/verify_nbtree.c b/contrib/amcheck/verify_nbtree.c
index c3380895a9..105945ee3b 100644
--- a/contrib/amcheck/verify_nbtree.c
+++ b/contrib/amcheck/verify_nbtree.c
@@ -23,8 +23,10 @@
  */
 #include "postgres.h"
 
+#include "access/htup_details.h"
 #include "access/nbtree.h"
 #include "access/transam.h"
+#include "access/xact.h"
 #include "catalog/index.h"
 #include "catalog/pg_am.h"
 #include "commands/tablecmds.h"
@@ -360,7 +362,30 @@ bt_check_every_level(Relation rel, Relation heaprel, bool readonly,
 		 * IndexBuildHeapScan().
 		 */
 		if (!state->readonly)
+		{
 			snapshot = RegisterSnapshot(GetTransactionSnapshot());
+
+			/*
+			 * GetTransactionSnapshot() always acquires a new MVCC snapshot in
+			 * READ COMMITTED mode.  A new snapshot is guaranteed to have all
+			 * the entries it requires in the index.
+			 *
+			 * We must defend against the possibility that an old xact snapshot
+			 * was returned at higher isolation levels when that snapshot is
+			 * not safe for index scans of the target index.  This is possible
+			 * when the snapshot sees tuples that are before the index's
+			 * indcheckxmin horizon.  Throwing an error here should be very
+			 * rare.  It doesn't seem worth using a secondary snapshot to avoid
+			 * this.
+			 */
+			if (IsolationUsesXactSnapshot() && rel->rd_index->indcheckxmin &&
+				!TransactionIdPrecedes(HeapTupleHeaderGetXmin(rel->rd_indextuple->t_data),
+									   snapshot->xmin))
+				ereport(ERROR,
+						(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
+						 errmsg("index \"%s\" cannot be verified using transaction snapshot",
+								RelationGetRelationName(rel))));
+		}
 	}
 
 	/* Create context for page */
-- 
2.14.1