static void ResetReindexProcessing(void);
static void SetReindexPending(List *indexes);
static void RemoveReindexPending(Oid indexOid);
-static void ResetReindexPending(void);
/*
newIndexForm->indisclustered = oldIndexForm->indisclustered;
/*
- * Mark the new index as valid, and the old index as invalid similarly
- * to what index_set_state_flags() does.
+ * Mark the new index as valid, and the old index as invalid similarly to
+ * what index_set_state_flags() does.
*/
newIndexForm->indisvalid = true;
oldIndexForm->indisvalid = false;
indexInfo->ii_ExclusionStrats = NULL;
}
- /* ensure SetReindexProcessing state isn't leaked */
- PG_TRY();
- {
- /* Suppress use of the target index while rebuilding it */
- SetReindexProcessing(heapId, indexId);
+ /* Suppress use of the target index while rebuilding it */
+ SetReindexProcessing(heapId, indexId);
- /* Create a new physical relation for the index */
- RelationSetNewRelfilenode(iRel, persistence);
+ /* Create a new physical relation for the index */
+ RelationSetNewRelfilenode(iRel, persistence);
- /* Initialize the index and rebuild */
- /* Note: we do not need to re-establish pkey setting */
- index_build(heapRelation, iRel, indexInfo, true, true);
- }
- PG_FINALLY();
- {
- /* Make sure flag gets cleared on error exit */
- ResetReindexProcessing();
- }
- PG_END_TRY();
+ /* Initialize the index and rebuild */
+ /* Note: we do not need to re-establish pkey setting */
+ index_build(heapRelation, iRel, indexInfo, true, true);
+
+ /* Re-allow use of target index */
+ ResetReindexProcessing();
/*
* If the index is marked invalid/not-ready/dead (ie, it's from a failed
Relation rel;
Oid toast_relid;
List *indexIds;
+ char persistence;
bool result;
+ ListCell *indexId;
int i;
/*
*/
indexIds = RelationGetIndexList(rel);
- PG_TRY();
+ if (flags & REINDEX_REL_SUPPRESS_INDEX_USE)
{
- ListCell *indexId;
- char persistence;
+ /* Suppress use of all the indexes until they are rebuilt */
+ SetReindexPending(indexIds);
- if (flags & REINDEX_REL_SUPPRESS_INDEX_USE)
- {
- /* Suppress use of all the indexes until they are rebuilt */
- SetReindexPending(indexIds);
+ /*
+ * Make the new heap contents visible --- now things might be
+ * inconsistent!
+ */
+ CommandCounterIncrement();
+ }
- /*
- * Make the new heap contents visible --- now things might be
- * inconsistent!
- */
- CommandCounterIncrement();
- }
+ /*
+ * Compute persistence of indexes: same as that of owning rel, unless
+ * caller specified otherwise.
+ */
+ if (flags & REINDEX_REL_FORCE_INDEXES_UNLOGGED)
+ persistence = RELPERSISTENCE_UNLOGGED;
+ else if (flags & REINDEX_REL_FORCE_INDEXES_PERMANENT)
+ persistence = RELPERSISTENCE_PERMANENT;
+ else
+ persistence = rel->rd_rel->relpersistence;
+
+ /* Reindex all the indexes. */
+ i = 1;
+ foreach(indexId, indexIds)
+ {
+ Oid indexOid = lfirst_oid(indexId);
+ Oid indexNamespaceId = get_rel_namespace(indexOid);
/*
- * Compute persistence of indexes: same as that of owning rel, unless
- * caller specified otherwise.
+ * Skip any invalid indexes on a TOAST table. These can only be
+ * duplicate leftovers from a failed REINDEX CONCURRENTLY, and if
+ * rebuilt it would not be possible to drop them anymore.
*/
- if (flags & REINDEX_REL_FORCE_INDEXES_UNLOGGED)
- persistence = RELPERSISTENCE_UNLOGGED;
- else if (flags & REINDEX_REL_FORCE_INDEXES_PERMANENT)
- persistence = RELPERSISTENCE_PERMANENT;
- else
- persistence = rel->rd_rel->relpersistence;
-
- /* Reindex all the indexes. */
- i = 1;
- foreach(indexId, indexIds)
+ if (IsToastNamespace(indexNamespaceId) &&
+ !get_index_isvalid(indexOid))
{
- Oid indexOid = lfirst_oid(indexId);
- Oid indexNamespaceId = get_rel_namespace(indexOid);
-
- /*
- * Skip any invalid indexes on a TOAST table. These can only be
- * duplicate leftovers from a failed REINDEX CONCURRENTLY, and if
- * rebuilt it would not be possible to drop them anymore.
- */
- if (IsToastNamespace(indexNamespaceId) &&
- !get_index_isvalid(indexOid))
- {
- ereport(WARNING,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("cannot reindex invalid index \"%s.%s\" on TOAST table, skipping",
- get_namespace_name(indexNamespaceId),
- get_rel_name(indexOid))));
- continue;
- }
+ ereport(WARNING,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot reindex invalid index \"%s.%s\" on TOAST table, skipping",
+ get_namespace_name(indexNamespaceId),
+ get_rel_name(indexOid))));
+ continue;
+ }
- reindex_index(indexOid, !(flags & REINDEX_REL_CHECK_CONSTRAINTS),
- persistence, options);
+ reindex_index(indexOid, !(flags & REINDEX_REL_CHECK_CONSTRAINTS),
+ persistence, options);
- CommandCounterIncrement();
+ CommandCounterIncrement();
- /* Index should no longer be in the pending list */
- Assert(!ReindexIsProcessingIndex(indexOid));
+ /* Index should no longer be in the pending list */
+ Assert(!ReindexIsProcessingIndex(indexOid));
- /* Set index rebuild count */
- pgstat_progress_update_param(PROGRESS_CLUSTER_INDEX_REBUILD_COUNT,
- i);
- i++;
- }
+ /* Set index rebuild count */
+ pgstat_progress_update_param(PROGRESS_CLUSTER_INDEX_REBUILD_COUNT,
+ i);
+ i++;
}
- PG_FINALLY();
- {
- /* Make sure list gets cleared on error exit */
- ResetReindexPending();
- }
- PG_END_TRY();
/*
* Close rel, but continue to hold the lock.
static Oid currentlyReindexedHeap = InvalidOid;
static Oid currentlyReindexedIndex = InvalidOid;
static List *pendingReindexedIndexes = NIL;
+static int reindexingNestLevel = 0;
/*
* ReindexIsProcessingHeap
/*
* SetReindexProcessing
* Set flag that specified heap/index are being reindexed.
- *
- * NB: caller must use a PG_TRY block to ensure ResetReindexProcessing is done.
*/
static void
SetReindexProcessing(Oid heapOid, Oid indexOid)
currentlyReindexedIndex = indexOid;
/* Index is no longer "pending" reindex. */
RemoveReindexPending(indexOid);
+ /* This may have been set already, but in case it isn't, do so now. */
+ reindexingNestLevel = GetCurrentTransactionNestLevel();
}
/*
static void
ResetReindexProcessing(void)
{
- /* This may be called in leader error path */
currentlyReindexedHeap = InvalidOid;
currentlyReindexedIndex = InvalidOid;
+ /* reindexingNestLevel remains set till end of (sub)transaction */
}
/*
* SetReindexPending
* Mark the given indexes as pending reindex.
*
- * NB: caller must use a PG_TRY block to ensure ResetReindexPending is done.
- * Also, we assume that the current memory context stays valid throughout.
+ * NB: we assume that the current memory context stays valid throughout.
*/
static void
SetReindexPending(List *indexes)
if (IsInParallelMode())
elog(ERROR, "cannot modify reindex state during a parallel operation");
pendingReindexedIndexes = list_copy(indexes);
+ reindexingNestLevel = GetCurrentTransactionNestLevel();
}
/*
}
/*
- * ResetReindexPending
- * Unset reindex-pending status.
+ * ResetReindexState
+ * Clear all reindexing state during (sub)transaction abort.
*/
-static void
-ResetReindexPending(void)
+void
+ResetReindexState(int nestLevel)
{
- /* This may be called in leader error path */
- pendingReindexedIndexes = NIL;
+ /*
+ * Because reindexing is not re-entrant, we don't need to cope with nested
+ * reindexing states. We just need to avoid messing up the outer-level
+ * state in case a subtransaction fails within a REINDEX. So checking the
+ * current nest level against that of the reindex operation is sufficient.
+ */
+ if (reindexingNestLevel >= nestLevel)
+ {
+ currentlyReindexedHeap = InvalidOid;
+ currentlyReindexedIndex = InvalidOid;
+
+ /*
+ * We needn't try to release the contents of pendingReindexedIndexes;
+ * that list should be in a transaction-lifespan context, so it will
+ * go away automatically.
+ */
+ pendingReindexedIndexes = NIL;
+
+ reindexingNestLevel = 0;
+ }
}
/*
lappend_oid(pendingReindexedIndexes,
sistate->pendingReindexedIndexes[c]);
MemoryContextSwitchTo(oldcontext);
+
+ /* Note the worker has its own transaction nesting level */
+ reindexingNestLevel = GetCurrentTransactionNestLevel();
}