On Fri, Jun 3, 2016 at 4:24 PM, Kevin Grittner <kgri...@gmail.com> wrote:

> Consequently, causing the index to be ignored in planning when
> using the old index

That last line should have read "using an old snapshot"

> is not a nice optimization, but necessary for
> correctness.  We already have logic to do this for other cases
> (like HOT updates), so it is a matter of tying in to that existing
> code correctly.  This won't be all that novel.

Just to demonstrate that, the minimal patch to fix behavior in this
area would be:

diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 31a1438..6c379da 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -2268,6 +2268,9 @@ IndexBuildHeapRangeScan(Relation heapRelation,
        Assert(numblocks == InvalidBlockNumber);
    }

+   if (old_snapshot_threshold >= 0)
+       indexInfo->ii_BrokenHotChain = true;
+
    reltuples = 0;

    /*

Of course, ii_BrokenHotChain should be renamed to something like
ii_UnsafeForOldSnapshots, and some comments need to be updated; but
the above is the substance of it.

Attached is what I have so far.  I'm still looking at what other
comments might need to be adjusted, but thought I should put this
much out for comment now.

--
Kevin Grittner
EDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 31a1438..b072985 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1672,7 +1672,7 @@ BuildIndexInfo(Relation index)
 
 	/* initialize index-build state to default */
 	ii->ii_Concurrent = false;
-	ii->ii_BrokenHotChain = false;
+	ii->ii_UnsafeForOldSnapshots = false;
 
 	return ii;
 }
@@ -2060,7 +2060,7 @@ index_build(Relation heapRelation,
 	 * about any concurrent readers of the tuple; no other transaction can see
 	 * it yet.
 	 */
-	if (indexInfo->ii_BrokenHotChain && !isreindex &&
+	if (indexInfo->ii_UnsafeForOldSnapshots && !isreindex &&
 		!indexInfo->ii_Concurrent)
 	{
 		Oid			indexId = RelationGetRelid(indexRelation);
@@ -2137,11 +2137,11 @@ index_build(Relation heapRelation,
  * so here because the AM might reject some of the tuples for its own reasons,
  * such as being unable to store NULLs.
  *
- * A side effect is to set indexInfo->ii_BrokenHotChain to true if we detect
- * any potentially broken HOT chains.  Currently, we set this if there are
- * any RECENTLY_DEAD or DELETE_IN_PROGRESS entries in a HOT chain, without
- * trying very hard to detect whether they're really incompatible with the
- * chain tip.
+ * A side effect is to set indexInfo->ii_UnsafeForOldSnapshots to true if we
+ * detect any potentially broken HOT chains or if old_snapshot_threshold is
+ * set to allow early pruning/vacuuuming.  Currently, we set this based on
+ * fairly simple tests; it is not guaranteed that using the index would cause
+ * a problem when set, but if the flag is clear it is guaranteed to be safe.
  */
 double
 IndexBuildHeapScan(Relation heapRelation,
@@ -2268,6 +2268,14 @@ IndexBuildHeapRangeScan(Relation heapRelation,
 		Assert(numblocks == InvalidBlockNumber);
 	}
 
+	/*
+	 * If allowing early pruning/vacuuming, the index cannot be considered
+	 * safe for old snapshots, since entries could be missing and lsn is set
+	 * to InvalidXLogRecPtr in all pages of the new index.
+	 */
+	if (old_snapshot_threshold >= 0)
+		indexInfo->ii_UnsafeForOldSnapshots = true;
+
 	reltuples = 0;
 
 	/*
@@ -2361,7 +2369,7 @@ IndexBuildHeapRangeScan(Relation heapRelation,
 					{
 						indexIt = false;
 						/* mark the index as unsafe for old snapshots */
-						indexInfo->ii_BrokenHotChain = true;
+						indexInfo->ii_UnsafeForOldSnapshots = true;
 					}
 					else
 						indexIt = true;
@@ -2488,7 +2496,7 @@ IndexBuildHeapRangeScan(Relation heapRelation,
 						 */
 						indexIt = false;
 						/* mark the index as unsafe for old snapshots */
-						indexInfo->ii_BrokenHotChain = true;
+						indexInfo->ii_UnsafeForOldSnapshots = true;
 					}
 					else
 					{
@@ -3409,9 +3417,9 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
 					 !indexForm->indisready ||
 					 !indexForm->indislive);
 		if (index_bad ||
-			(indexForm->indcheckxmin && !indexInfo->ii_BrokenHotChain))
+			(indexForm->indcheckxmin && !indexInfo->ii_UnsafeForOldSnapshots))
 		{
-			if (!indexInfo->ii_BrokenHotChain)
+			if (!indexInfo->ii_UnsafeForOldSnapshots)
 				indexForm->indcheckxmin = false;
 			else if (index_bad)
 				indexForm->indcheckxmin = true;
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index 564e10e..8dcac7e 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -314,7 +314,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
 	indexInfo->ii_Unique = true;
 	indexInfo->ii_ReadyForInserts = true;
 	indexInfo->ii_Concurrent = false;
-	indexInfo->ii_BrokenHotChain = false;
+	indexInfo->ii_UnsafeForOldSnapshots = false;
 
 	collationObjectId[0] = InvalidOid;
 	collationObjectId[1] = InvalidOid;
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index d14d540..a3d8bd2 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -557,7 +557,7 @@ DefineIndex(Oid relationId,
 	/* In a concurrent build, mark it not-ready-for-inserts */
 	indexInfo->ii_ReadyForInserts = !stmt->concurrent;
 	indexInfo->ii_Concurrent = stmt->concurrent;
-	indexInfo->ii_BrokenHotChain = false;
+	indexInfo->ii_UnsafeForOldSnapshots = false;
 
 	typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
 	collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
@@ -761,7 +761,7 @@ DefineIndex(Oid relationId,
 	indexInfo = BuildIndexInfo(indexRelation);
 	Assert(!indexInfo->ii_ReadyForInserts);
 	indexInfo->ii_Concurrent = true;
-	indexInfo->ii_BrokenHotChain = false;
+	indexInfo->ii_UnsafeForOldSnapshots = false;
 
 	/* Now build the index */
 	index_build(rel, indexRelation, indexInfo, stmt->primary, false);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index ee4e189..2ba4230 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -49,10 +49,12 @@
  *		Unique				is it a unique index?
  *		ReadyForInserts		is it valid for inserts?
  *		Concurrent			are we doing a concurrent index build?
- *		BrokenHotChain		did we detect any broken HOT chains?
+ *		UnsafeForOldSnapshots did we detect reasons not to use the index with
+ * 							old snapshots (like broken HOT chains or enabled
+ * 							early pruning/vacuuming)?
  *
- * ii_Concurrent and ii_BrokenHotChain are used only during index build;
- * they're conventionally set to false otherwise.
+ * ii_Concurrent and ii_UnsafeForOldSnapshots are used only during index
+ * build; they're conventionally set to false otherwise.
  * ----------------
  */
 typedef struct IndexInfo
@@ -73,7 +75,7 @@ typedef struct IndexInfo
 	bool		ii_Unique;
 	bool		ii_ReadyForInserts;
 	bool		ii_Concurrent;
-	bool		ii_BrokenHotChain;
+	bool		ii_UnsafeForOldSnapshots;
 } IndexInfo;
 
 /* ----------------
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to