HeapTuple indexTuple;
Form_pg_index indexForm;
+ /*
+ * Broken HOT chains should not get reported in system catalogs; in
+ * particular it would be quite dangerous to try to modify the index's
+ * pg_index entry if we are reindexing pg_index itself.
+ */
+ Assert(!IsSystemRelation(heapRelation));
+
pg_index = heap_open(IndexRelationId, RowExclusiveLock);
indexTuple = SearchSysCacheCopy(INDEXRELID,
* 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 entries in a HOT chain, without trying very hard to
- * detect whether they're really incompatible with the chain tip.
+ * detect whether they're really incompatible with the chain tip. However,
+ * we do not ever set ii_BrokenHotChain true when the relation is a system
+ * catalog. This is to avoid problematic behavior when reindexing pg_index
+ * itself: we can't safely change the index's indcheckxmin field when we're
+ * partway through such an operation. It should be okay since the set of
+ * indexes on a system catalog ought not change during concurrent operations,
+ * so that no HOT chain in it could ever become broken.
*/
double
IndexBuildHeapScan(Relation heapRelation,
IndexBuildCallback callback,
void *callback_state)
{
+ bool is_system_catalog;
HeapScanDesc scan;
HeapTuple heapTuple;
Datum values[INDEX_MAX_KEYS];
*/
Assert(OidIsValid(indexRelation->rd_rel->relam));
+ /* Remember if it's a system catalog */
+ is_system_catalog = IsSystemRelation(heapRelation);
+
/*
* Need an EState for evaluation of index expressions and partial-index
* predicates. Also a slot to hold the current tuple.
{
indexIt = false;
/* mark the index as unsafe for old snapshots */
- indexInfo->ii_BrokenHotChain = true;
+ if (!is_system_catalog)
+ indexInfo->ii_BrokenHotChain = true;
}
else if (indexInfo->ii_BrokenHotChain)
indexIt = false;
{
indexIt = false;
/* mark the index as unsafe for old snapshots */
- indexInfo->ii_BrokenHotChain = true;
+ if (!is_system_catalog)
+ indexInfo->ii_BrokenHotChain = true;
}
else if (indexInfo->ii_BrokenHotChain)
indexIt = false;
* 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.
+ *
+ * When reindexing a system catalog, don't do any of this --- it would be
+ * particularly risky to try to modify pg_index while we are reindexing
+ * pg_index itself. We don't support CREATE INDEX CONCURRENTLY on system
+ * catalogs anyway, and they should never have indcheckxmin set either.
*/
- pg_index = heap_open(IndexRelationId, RowExclusiveLock);
+ if (!IsSystemRelation(heapRelation))
+ {
+ pg_index = heap_open(IndexRelationId, RowExclusiveLock);
- indexTuple = SearchSysCacheCopy(INDEXRELID,
- ObjectIdGetDatum(indexId),
- 0, 0, 0);
- if (!HeapTupleIsValid(indexTuple))
- elog(ERROR, "cache lookup failed for index %u", indexId);
- indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
+ indexTuple = SearchSysCacheCopy(INDEXRELID,
+ ObjectIdGetDatum(indexId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(indexTuple))
+ elog(ERROR, "cache lookup failed for index %u", indexId);
+ indexForm = (Form_pg_index) GETSTRUCT(indexTuple);
- if (!indexForm->indisvalid || !indexForm->indisready ||
- (indexForm->indcheckxmin && !indexInfo->ii_BrokenHotChain))
- {
- indexForm->indisvalid = true;
- indexForm->indisready = true;
- if (!indexInfo->ii_BrokenHotChain)
- indexForm->indcheckxmin = false;
- simple_heap_update(pg_index, &indexTuple->t_self, indexTuple);
- CatalogUpdateIndexes(pg_index, indexTuple);
+ if (!indexForm->indisvalid || !indexForm->indisready ||
+ (indexForm->indcheckxmin && !indexInfo->ii_BrokenHotChain))
+ {
+ indexForm->indisvalid = true;
+ indexForm->indisready = true;
+ if (!indexInfo->ii_BrokenHotChain)
+ indexForm->indcheckxmin = false;
+ simple_heap_update(pg_index, &indexTuple->t_self, indexTuple);
+ CatalogUpdateIndexes(pg_index, indexTuple);
+ }
+ heap_close(pg_index, RowExclusiveLock);
}
- heap_close(pg_index, RowExclusiveLock);
/* Close rels, but keep locks */
index_close(iRel, NoLock);