diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index 080d80e296b..d6dce8f4f20 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -1127,7 +1127,7 @@ build_indices(void) heap = heap_open(ILHead->il_heap, NoLock); ind = index_open(ILHead->il_ind, NoLock); - index_build(heap, ind, ILHead->il_info, false); + index_build(heap, ind, ILHead->il_info, false, false); index_close(ind, NoLock); heap_close(heap, NoLock); diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index d74700f716f..3cd6d08af4f 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -2451,7 +2451,7 @@ RelationTruncateIndexes(Relation heapRelation) /* Initialize the index and rebuild */ /* Note: we do not need to re-establish pkey setting */ - index_build(heapRelation, currentIndex, indexInfo, false); + index_build(heapRelation, currentIndex, indexInfo, false, true); /* We're done with this index */ index_close(currentIndex, NoLock); diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index caa985a791f..999b5da1fdf 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -957,7 +957,7 @@ index_create(Oid heapRelationId, } else { - index_build(heapRelation, indexRelation, indexInfo, isprimary); + index_build(heapRelation, indexRelation, indexInfo, isprimary, false); } /* @@ -1389,8 +1389,11 @@ index_update_stats(Relation rel, * entries of the index and heap relation as needed, using statistics * returned by ambuild as well as data passed by the caller. * - * Note: when reindexing an existing index, isprimary can be false; - * the index is already properly marked and need not be re-marked. + * isprimary tells whether to mark the index as a primary-key index. + * isreindex indicates we are recreating a previously-existing index. + * + * Note: when reindexing an existing index, isprimary can be false even if + * the index is a PK; it's already properly marked and need not be re-marked. * * Note: before Postgres 8.2, the passed-in heap and index Relations * were automatically closed by this routine. This is no longer the case. @@ -1400,7 +1403,8 @@ void index_build(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, - bool isprimary) + bool isprimary, + bool isreindex) { RegProcedure procedure; IndexBuildResult *stats; @@ -1454,8 +1458,15 @@ index_build(Relation heapRelation, * If we found any potentially broken HOT chains, mark the index as not * being usable until the current transaction is below the event horizon. * See src/backend/access/heap/README.HOT for discussion. + * + * However, when reindexing an existing index, we should do nothing here. + * Any HOT chains that are broken with respect to the index must predate + * the index's original creation, so there is no need to change the + * index's usability horizon. Moreover, we *must not* try to change + * the index's pg_index entry while reindexing pg_index itself, and this + * optimization nicely prevents that. */ - if (indexInfo->ii_BrokenHotChain) + if (indexInfo->ii_BrokenHotChain && !isreindex) { Oid indexId = RelationGetRelid(indexRelation); Relation pg_index; @@ -1470,6 +1481,9 @@ index_build(Relation heapRelation, elog(ERROR, "cache lookup failed for index %u", indexId); indexForm = (Form_pg_index) GETSTRUCT(indexTuple); + /* If it's a new index, indcheckxmin shouldn't be set ... */ + Assert(!indexForm->indcheckxmin); + indexForm->indcheckxmin = true; simple_heap_update(pg_index, &indexTuple->t_self, indexTuple); CatalogUpdateIndexes(pg_index, indexTuple); @@ -2461,7 +2475,7 @@ reindex_index(Oid indexId, bool skip_constraint_checks) /* Initialize the index and rebuild */ /* Note: we do not need to re-establish pkey setting */ - index_build(heapRelation, iRel, indexInfo, false); + index_build(heapRelation, iRel, indexInfo, false, true); } PG_CATCH(); { @@ -2481,6 +2495,16 @@ reindex_index(Oid indexId, bool skip_constraint_checks) * We can also reset indcheckxmin, because we have now done a * non-concurrent index build, *except* in the case where index_build * found some still-broken HOT chains. + * + * Note that it is important to not update the pg_index entry if we don't + * have to, because updating it will move the index's usability horizon + * (recorded as the tuple's xmin value) if indcheckxmin is true. We don't + * really want REINDEX to move the usability horizon forward ever, but we + * have no choice if we are to fix indisvalid or indisready. Of course, + * clearing indcheckxmin eliminates the issue, so we're happy to do that + * if we can. Another reason for caution here is that while reindexing + * pg_index itself, we must not try to update it. We assume that + * pg_index's indexes will always have these flags in their clean state. */ if (!skipped_constraint) { diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index 61020dcbe74..153ed9a516b 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -1360,6 +1360,12 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, * advantage to the other order anyway because this is all transactional, * so no chance to reclaim disk space before commit. We do not need a * final CommandCounterIncrement() because reindex_relation does it. + * + * Note: because index_build is called via reindex_relation, it will never + * set indcheckxmin true for the indexes. This is OK even though in some + * sense we are building new indexes rather than rebuilding existing ones, + * because the new heap won't contain any HOT chains at all, let alone + * broken ones, so it can't be necessary to set indcheckxmin. */ reindex_flags = REINDEX_SUPPRESS_INDEX_USE; if (check_constraints) diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index a129511128b..775aba34922 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -584,7 +584,7 @@ DefineIndex(RangeVar *heapRelation, indexInfo->ii_BrokenHotChain = false; /* Now build the index */ - index_build(rel, indexRelation, indexInfo, primary); + index_build(rel, indexRelation, indexInfo, primary, false); /* Close both the relations, but keep the locks */ heap_close(rel, NoLock); diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h index 18f17037b7b..9728d791b6a 100644 --- a/src/include/catalog/index.h +++ b/src/include/catalog/index.h @@ -59,7 +59,8 @@ extern void FormIndexDatum(IndexInfo *indexInfo, extern void index_build(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, - bool isprimary); + bool isprimary, + bool isreindex); extern double IndexBuildHeapScan(Relation heapRelation, Relation indexRelation,