agora inbox for [email protected]
help / color / mirror / Atom feed[PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
157+ messages / 2 participants
[nested] [flat]
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once..
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
The utility of this is to reindex N partitions in 2 transactions, rather than
2*N transactions.
---
src/backend/commands/indexcmds.c | 258 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 182 insertions(+), 80 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index b21555b6cf..f5fea14ff4 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -2636,7 +2647,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -3002,20 +3021,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_indexes(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -3060,38 +3128,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
-
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_indexes(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_indexes(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3254,18 +3342,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3274,13 +3353,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3553,6 +3625,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ ReindexParams *params, MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -4026,42 +4161,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 830fdddf24..6f41adf736 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--QTprm0S8XgL7H0Dt
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v13-0006-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once
@ 2020-11-01 18:25 Justin Pryzby <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Justin Pryzby @ 2020-11-01 18:25 UTC (permalink / raw)
---
src/backend/commands/indexcmds.c | 262 ++++++++++++++-------
src/test/regress/expected/create_index.out | 4 +-
2 files changed, 185 insertions(+), 81 deletions(-)
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 739bd14001..08d44a1999 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -102,6 +102,8 @@ static void ReindexMultipleInternal(List *relids,
ReindexParams *params);
static bool ReindexRelationConcurrently(Oid relationOid,
ReindexParams *params);
+static List *ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds,
+ int options, MemoryContext private_context);
static void update_relispartition(Oid relationId, bool newval);
static inline void set_indexsafe_procflags(void);
@@ -124,6 +126,15 @@ typedef struct ReindexErrorInfo
char relkind;
} ReindexErrorInfo;
+/* Argument to ReindexIndexConcurrently takes a List* of these */
+typedef struct ReindexIndexInfo
+{
+ Oid indexId;
+ Oid tableId;
+ Oid amId;
+ bool safe; /* for set_indexsafe_procflags */
+} ReindexIndexInfo;
+
/*
* CheckIndexCompatible
* Determine whether an existing index definition is compatible with a
@@ -1635,7 +1646,9 @@ DefineIndex(Oid relationId,
static void
reindex_invalid_child_indexes(Oid indexRelationId)
{
- ReindexParams params = { .options = REINDEXOPT_CONCURRENTLY };
+ ReindexParams params = {
+ .options = REINDEXOPT_CONCURRENTLY | REINDEXOPT_SKIPVALID,
+ };
/*
* CIC needs to mark a partitioned index as VALID, which itself
@@ -2607,7 +2620,15 @@ ReindexIndex(RangeVar *indexRelation, ReindexParams *params, bool isTopLevel)
ReindexPartitions(indOid, params, isTopLevel);
else if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
persistence != RELPERSISTENCE_TEMP)
- ReindexRelationConcurrently(indOid, params);
+ {
+ ReindexIndexInfo idxinfo = {
+ .indexId = indOid,
+ /* other fields set later */
+ };
+ ReindexIndexesConcurrently(list_make1(&idxinfo),
+ list_make1_oid(IndexGetRelation(indOid, false)),
+ params->options, CurrentMemoryContext);
+ }
else
{
ReindexParams newparams = *params;
@@ -2938,20 +2959,69 @@ reindex_error_callback(void *arg)
errinfo->relnamespace, errinfo->relname);
}
+
+/*
+ * Given a list of index oids, return a list of leaf partitions by removing
+ * any intermediate parents. heaprels is populated with the corresponding
+ * tables.
+ */
+static List *
+leaf_partitions(List *inhoids, int options, List **heaprels)
+{
+ List *partitions = NIL;
+ ListCell *lc;
+
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Oid tableoid;
+ Relation table;
+ char partkind = get_rel_relkind(partoid);
+
+ /*
+ * This discards partitioned indexes and foreign tables.
+ */
+ if (!RELKIND_HAS_STORAGE(partkind))
+ continue;
+
+ Assert(partkind == RELKIND_INDEX);
+
+ /* Skip invalid indexes, if requested */
+ if ((options & REINDEXOPT_SKIPVALID) != 0 &&
+ get_index_isvalid(partoid))
+ continue;
+
+ /* (try to) Open the table, with lock */
+ tableoid = IndexGetRelation(partoid, false);
+ table = table_open(tableoid, ShareLock);
+ table_close(table, NoLock);
+
+ /* Save partition OID in current MemoryContext */
+ partitions = lappend_oid(partitions, partoid);
+ *heaprels = lappend_oid(*heaprels, tableoid);
+ }
+
+ return partitions;
+}
+
+
/*
* ReindexPartitions
*
* Reindex a set of partitions, per the partitioned index or table given
* by the caller.
+ * XXX: should be further refactored with logic from ReindexRelationConcurrently
*/
static void
ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
{
- List *partitions = NIL;
+ List *partitions = NIL,
+ *heaprels = NIL;
char relkind = get_rel_relkind(relid);
char *relname = get_rel_name(relid);
char *relnamespace = get_namespace_name(get_rel_namespace(relid));
MemoryContext reindex_context;
+ MemoryContext old_context;
List *inhoids;
ListCell *lc;
ErrorContextCallback errcallback;
@@ -2996,38 +3066,58 @@ ReindexPartitions(Oid relid, ReindexParams *params, bool isTopLevel)
* The list of relations to reindex are the physical partitions of the
* tree so discard any partitioned table or index.
*/
- foreach(lc, inhoids)
- {
- Oid partoid = lfirst_oid(lc);
- char partkind = get_rel_relkind(partoid);
- MemoryContext old_context;
- /*
- * This discards partitioned tables, partitioned indexes and foreign
- * tables.
- */
- if (!RELKIND_HAS_STORAGE(partkind))
- continue;
-
- /* Skip invalid indexes, if requested */
- if ((params->options & REINDEXOPT_SKIPVALID) != 0 &&
- get_index_isvalid(partoid))
- continue;
+ if (relkind == RELKIND_PARTITIONED_INDEX)
+ {
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partitions = leaf_partitions(inhoids, params->options, &heaprels);
+ MemoryContextSwitchTo(old_context);
+ } else {
+ /* Loop over parent tables */
+ foreach(lc, inhoids)
+ {
+ Oid partoid = lfirst_oid(lc);
+ Relation parttable;
+ List *partindexes;
+
+ parttable = table_open(partoid, ShareLock);
+ old_context = MemoryContextSwitchTo(reindex_context);
+ partindexes = RelationGetIndexList(parttable);
+ partindexes = leaf_partitions(partindexes, params->options, &heaprels);
+ partitions = list_concat(partitions, partindexes);
+
+ MemoryContextSwitchTo(old_context);
+ table_close(parttable, ShareLock);
+ }
+ }
- Assert(partkind == RELKIND_INDEX ||
- partkind == RELKIND_RELATION);
+ if ((params->options & REINDEXOPT_CONCURRENTLY) != 0 &&
+ relkind == RELKIND_PARTITIONED_INDEX &&
+ get_rel_persistence(relid) != RELPERSISTENCE_TEMP)
+ {
+ List *idxinfos = NIL;
+ ReindexIndexInfo *idxinfo;
- /* Save partition OID */
old_context = MemoryContextSwitchTo(reindex_context);
- partitions = lappend_oid(partitions, partoid);
+ foreach (lc, partitions)
+ {
+ Oid partoid = lfirst_oid(lc);
+ idxinfo = palloc(sizeof(ReindexIndexInfo));
+ idxinfo->indexId = partoid;
+ /* other fields set later */
+ idxinfos = lappend(idxinfos, idxinfo);
+ }
MemoryContextSwitchTo(old_context);
- }
- /*
- * Process each partition listed in a separate transaction. Note that
- * this commits and then starts a new transaction immediately.
- */
- ReindexMultipleInternal(partitions, params);
+ /* Process all indexes in a single loop */
+ ReindexIndexesConcurrently(idxinfos, heaprels, params->options, reindex_context);
+ } else {
+ /*
+ * Process each partition listed in a separate transaction. Note that
+ * this commits and then starts a new transaction immediately.
+ */
+ ReindexMultipleInternal(partitions, params);
+ }
/*
* If indexes exist on all of the partitioned table's children, and we
@@ -3172,18 +3262,9 @@ ReindexMultipleInternal(List *relids, ReindexParams *params)
static bool
ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
{
- typedef struct ReindexIndexInfo
- {
- Oid indexId;
- Oid tableId;
- Oid amId;
- bool safe; /* for set_indexsafe_procflags */
- } ReindexIndexInfo;
List *heapRelationIds = NIL;
List *indexIds = NIL;
List *newIndexIds = NIL;
- List *relationLocks = NIL;
- List *lockTags = NIL;
ListCell *lc,
*lc2;
MemoryContext private_context;
@@ -3192,13 +3273,6 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
char *relationName = NULL;
char *relationNamespace = NULL;
PGRUsage ru0;
- const int progress_index[] = {
- PROGRESS_CREATEIDX_COMMAND,
- PROGRESS_CREATEIDX_PHASE,
- PROGRESS_CREATEIDX_INDEX_OID,
- PROGRESS_CREATEIDX_ACCESS_METHOD_OID
- };
- int64 progress_vals[4];
/*
* Create a memory context that will survive forced transaction commits we
@@ -3449,6 +3523,69 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Assert(heapRelationIds != NIL);
+ /* Do the work */
+ newIndexIds = ReindexIndexesConcurrently(indexIds, heapRelationIds, params->options, private_context);
+
+ /* Log what we did */
+ if ((params->options & REINDEXOPT_VERBOSE) != 0)
+ {
+ if (relkind == RELKIND_INDEX)
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ else
+ {
+ foreach(lc, newIndexIds)
+ {
+ Oid indOid = lfirst_oid(lc);
+ ereport(INFO,
+ (errmsg("index \"%s.%s\" was reindexed",
+ get_namespace_name(get_rel_namespace(indOid)),
+ get_rel_name(indOid))));
+ /* Don't show rusage here, since it's not per index. */
+ }
+
+ ereport(INFO,
+ (errmsg("table \"%s.%s\" was reindexed",
+ relationNamespace, relationName),
+ errdetail("%s.",
+ pg_rusage_show(&ru0))));
+ }
+ }
+
+
+ MemoryContextDelete(private_context);
+
+ return true;
+}
+
+/*
+ * Reindex concurrently for an arbitrary list of index relations
+ * This is called by ReindexRelationConcurrently and
+ */
+static List *
+ReindexIndexesConcurrently(List *indexIds, List *heapRelationIds, int options,
+ MemoryContext private_context)
+{
+ List *newIndexIds = NIL;
+ List *relationLocks = NIL;
+ List *lockTags = NIL;
+
+ ListCell *lc,
+ *lc2;
+
+ MemoryContext oldcontext;
+
+ const int progress_index[] = {
+ PROGRESS_CREATEIDX_COMMAND,
+ PROGRESS_CREATEIDX_PHASE,
+ PROGRESS_CREATEIDX_INDEX_OID,
+ PROGRESS_CREATEIDX_ACCESS_METHOD_OID
+ };
+ int64 progress_vals[4];
+
/*-----
* Now we have all the indexes we want to process in indexIds.
*
@@ -3913,42 +4050,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
/* Start a new transaction to finish process properly */
StartTransactionCommand();
- /* Log what we did */
- if ((params->options & REINDEXOPT_VERBOSE) != 0)
- {
- if (relkind == RELKIND_INDEX)
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- else
- {
- foreach(lc, newIndexIds)
- {
- ReindexIndexInfo *idx = lfirst(lc);
- Oid indOid = idx->indexId;
-
- ereport(INFO,
- (errmsg("index \"%s.%s\" was reindexed",
- get_namespace_name(get_rel_namespace(indOid)),
- get_rel_name(indOid))));
- /* Don't show rusage here, since it's not per index. */
- }
-
- ereport(INFO,
- (errmsg("table \"%s.%s\" was reindexed",
- relationNamespace, relationName),
- errdetail("%s.",
- pg_rusage_show(&ru0))));
- }
- }
-
- MemoryContextDelete(private_context);
-
pgstat_progress_end_command();
- return true;
+ return newIndexIds;
}
/*
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index fc6afab58a..4a03ab2abb 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2470,12 +2470,12 @@ COMMIT;
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relation
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_class_oid_index; -- no catalog index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
-- These are the toast table and index of pg_authid.
REINDEX TABLE CONCURRENTLY pg_toast.pg_toast_1260; -- no catalog toast table
ERROR: cannot reindex system catalogs concurrently
REINDEX INDEX CONCURRENTLY pg_toast.pg_toast_1260_index; -- no catalog toast index
-ERROR: cannot reindex system catalogs concurrently
+ERROR: concurrent index creation on system catalog tables is not supported
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
ERROR: cannot reindex system catalogs concurrently
-- Warns about catalog relations
--
2.17.0
--MfFXiAuoTsnnDAfZ
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="v12-0005-More-refactoring.patch"
^ permalink raw reply [nested|flat] 157+ messages in thread
* [PATCH v1] Use open file description locks for data directory lockfile
@ 2025-12-18 17:21 Dmitrii Dolgov <[email protected]>
0 siblings, 0 replies; 157+ messages in thread
From: Dmitrii Dolgov @ 2025-12-18 17:21 UTC (permalink / raw)
When starting up, postmaster checks for an existing data directory lockfile. If
this file contains current process PID, it's assumed to be stale. Turns out
there is another possibility: we might be running in a PID namespace, and there
is another postgres running inside another PID namespace using the same data
directory. The result is that we don't see another process due to namespace
isolation and start concurrently with the other.
To prevent such situations, at startup use fcntl to get an exclusive open file
description lock for data directory lockfile. Since such locks are associated
with open file descriptors, meaning they're not affected by PID namespace
isolation. It's a "best effort" locking, intended to work with already existing
mechanism, not replace it.
This approach was discussed multiple times in the past, and usually was
rejected as the main work horse for the data directory lockfile due to:
* Portability issues. Open file description lock was a non-POSIX extension in
Linux and similar flock is from BSD standard. But looks like everybody agrees
that such locks make more sense than a typical advisory locks, and
F_OFD_SETLK made its way into POSIX.1 2024 [1].
* Issues with NFS. The current state of things here looks like this:
- NFSv3 doesn't implement open file description locks, they're converted to
advisory locks instead. Advisory locks are subject to namespace isolation,
meaning that processes in different PID namespaces will not see each other
advisory lock, and it's still possible to run multiple postgres
instances on the same data directory.
- NFSv4 uses a lease system for locking, I haven't found any mention of
conversion to advisory locks neither in the man page nor in RFC [2].
To summarize, the approach is now considered POSIX and should fix the described
problem everywhere, except NFSv3.
[1]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/fcntl.html
[2]: https://www.rfc-editor.org/rfc/rfc7530
---
configure | 14 ++++
configure.ac | 3 +
meson.build | 1 +
src/backend/utils/init/miscinit.c | 107 +++++++++++++++++++++++++-----
src/include/pg_config.h.in | 4 ++
5 files changed, 111 insertions(+), 18 deletions(-)
diff --git a/configure b/configure
index 14ad0a5006f..b176ac39799 100755
--- a/configure
+++ b/configure
@@ -16177,6 +16177,20 @@ cat >>confdefs.h <<_ACEOF
_ACEOF
+# Linux open file descriptor locks
+ac_fn_c_check_decl "$LINENO" "F_OFD_SETLK" "ac_cv_have_decl_F_OFD_SETLK" "#include <fcntl.h>
+"
+if test "x$ac_cv_have_decl_F_OFD_SETLK" = xyes; then :
+ ac_have_decl=1
+else
+ ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_F_OFD_SETLK $ac_have_decl
+_ACEOF
+
+
ac_fn_c_check_func "$LINENO" "explicit_bzero" "ac_cv_func_explicit_bzero"
if test "x$ac_cv_func_explicit_bzero" = xyes; then :
$as_echo "#define HAVE_EXPLICIT_BZERO 1" >>confdefs.h
diff --git a/configure.ac b/configure.ac
index 01b3bbc1be8..d6cf1f27771 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1838,6 +1838,9 @@ AC_CHECK_DECLS([memset_s], [], [], [#define __STDC_WANT_LIB_EXT1__ 1
# This is probably only present on macOS, but may as well check always
AC_CHECK_DECLS(F_FULLFSYNC, [], [], [#include <fcntl.h>])
+# Linux open file descriptor locks
+AC_CHECK_DECLS([F_OFD_SETLK], [], [], [#include <fcntl.h>])
+
AC_REPLACE_FUNCS(m4_normalize([
explicit_bzero
getopt
diff --git a/meson.build b/meson.build
index d7c5193d4ce..ad9ecad829f 100644
--- a/meson.build
+++ b/meson.build
@@ -2667,6 +2667,7 @@ decl_checks = [
['strnlen', 'string.h'],
['strsep', 'string.h'],
['timingsafe_bcmp', 'string.h'],
+ ['F_OFD_SETLK', 'fcntl.h'],
]
# Need to check for function declarations for these functions, because
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index fec79992c8d..78bb7df543e 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -68,6 +68,11 @@ static List *lock_files = NIL;
static Latch LocalLatchData;
+#ifdef HAVE_DECL_F_OFD_SETLK
+/* File descriptor for data directory lock file. */
+static int DataDirLockFD;
+#endif
+
/* ----------------------------------------------------------------
* ignoring system indexes support stuff
*
@@ -1117,6 +1122,45 @@ RestoreClientConnectionInfo(char *conninfo)
*-------------------------------------------------------------------------
*/
+/*
+ * Flock the data directory lockfile.
+ *
+ * Lock the data directory lockfile with an open file description lock. If the
+ * lock is already taken, it's a hard stop. It's only a best effort test, and
+ * any other errors are ignored. On succes the file descriptor is duplicated,
+ * to make sure there will be at least one open copy of it to keep the lock.
+ *
+ * filename is used only for reporting purposes.
+ */
+static void
+FlockDataDirLockFile(int fd, const char *filename)
+{
+
+#ifdef HAVE_DECL_F_OFD_SETLK
+ struct flock lock;
+
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+ lock.l_pid = 0;
+
+ if (fcntl(fd, F_OFD_SETLK, &lock) == -1)
+ {
+ if (errno == EAGAIN)
+ ereport(FATAL,
+ (errcode(ERRCODE_LOCK_FILE_EXISTS),
+ errmsg("cannot lock the lock file \"%s\"", filename),
+ errhint("Another server is starting.")));
+ else
+ elog(WARNING, "Failed locking file \"%s\", %m", filename);
+ }
+ else
+ DataDirLockFD = dup(fd);
+#endif
+
+}
+
/*
* proc_exit callback to remove lockfiles.
*/
@@ -1125,6 +1169,11 @@ UnlinkLockFiles(int status, Datum arg)
{
ListCell *l;
+#ifdef HAVE_DECL_F_OFD_SETLK
+ /* Close the file descriptor, which keeps the open file description lock */
+ close(DataDirLockFD);
+#endif
+
foreach(l, lock_files)
{
char *curfile = (char *) lfirst(l);
@@ -1171,22 +1220,32 @@ CreateLockFile(const char *filename, bool amPostmaster,
const char *envvar;
/*
- * If the PID in the lockfile is our own PID or our parent's or
- * grandparent's PID, then the file must be stale (probably left over from
- * a previous system boot cycle). We need to check this because of the
- * likelihood that a reboot will assign exactly the same PID as we had in
- * the previous reboot, or one that's only one or two counts larger and
- * hence the lockfile's PID now refers to an ancestor shell process. We
- * allow pg_ctl to pass down its parent shell PID (our grandparent PID)
- * via the environment variable PG_GRANDPARENT_PID; this is so that
- * launching the postmaster via pg_ctl can be just as reliable as
- * launching it directly. There is no provision for detecting
- * further-removed ancestor processes, but if the init script is written
- * carefully then all but the immediate parent shell will be root-owned
- * processes and so the kill test will fail with EPERM. Note that we
- * cannot get a false negative this way, because an existing postmaster
- * would surely never launch a competing postmaster or pg_ctl process
- * directly.
+ * If we find an already existing lockfile containing our own PID,
+ * there are few options:
+ *
+ * - There is another process, that we don't see due to PID namespace
+ * isolation, which is already running in this data directory.
+ *
+ * To prevent two concurrent processes working with the same data
+ * directory, we first try to lock the lockfile exclusively.
+ *
+ * - The file must be stale, probably left over from a previous system boot
+ * cycle. The same if the lockfile contains our parent's or grandparent's
+ * PID.
+ *
+ * We need to check this because of the likelihood that a reboot will
+ * assign exactly the same PID as we had in the previous reboot, or one
+ * that's only one or two counts larger and hence the lockfile's PID now
+ * refers to an ancestor shell process. We allow pg_ctl to pass down its
+ * parent shell PID (our grandparent PID) via the environment variable
+ * PG_GRANDPARENT_PID; this is so that launching the postmaster via
+ * pg_ctl can be just as reliable as launching it directly. There is no
+ * provision for detecting further-removed ancestor processes, but if the
+ * init script is written carefully then all but the immediate parent
+ * shell will be root-owned processes and so the kill test will fail with
+ * EPERM. Note that we cannot get a false negative this way, because an
+ * existing postmaster would surely never launch a competing postmaster
+ * or pg_ctl process directly.
*/
my_pid = getpid();
@@ -1222,7 +1281,11 @@ CreateLockFile(const char *filename, bool amPostmaster,
*/
fd = open(filename, O_RDWR | O_CREAT | O_EXCL, pg_file_create_mode);
if (fd >= 0)
- break; /* Success; exit the retry loop */
+ {
+ /* Success; lock and exit the retry loop */
+ FlockDataDirLockFile(fd, filename);
+ break;
+ }
/*
* Couldn't create the pid file. Probably it already exists.
@@ -1236,8 +1299,12 @@ CreateLockFile(const char *filename, bool amPostmaster,
/*
* Read the file to get the old owner's PID. Note race condition
* here: file might have been deleted since we tried to create it.
+ *
+ * We're going to use the same fd for flock, and want to create a write
+ * lock for the latter one. Since both fd and the lock have to be of
+ * the same type, open the file for read and write.
*/
- fd = open(filename, O_RDONLY, pg_file_create_mode);
+ fd = open(filename, O_RDWR, pg_file_create_mode);
if (fd < 0)
{
if (errno == ENOENT)
@@ -1247,6 +1314,10 @@ CreateLockFile(const char *filename, bool amPostmaster,
errmsg("could not open lock file \"%s\": %m",
filename)));
}
+
+ /* Try to lock the file. We stop here, if it's already locked. */
+ FlockDataDirLockFile(fd, filename);
+
pgstat_report_wait_start(WAIT_EVENT_LOCK_FILE_CREATE_READ);
if ((len = read(fd, buffer, sizeof(buffer) - 1)) < 0)
ereport(FATAL,
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 92fcc5f3063..c19a50f108e 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -83,6 +83,10 @@
don't. */
#undef HAVE_DECL_F_FULLFSYNC
+/* Define to 1 if you have the declaration of `F_OFD_SETLK', and to 0 if you
+ don't. */
+#undef HAVE_DECL_F_OFD_SETLK
+
/* Define to 1 if you have the declaration of
`LLVMCreateGDBRegistrationListener', and to 0 if you don't. */
#undef HAVE_DECL_LLVMCREATEGDBREGISTRATIONLISTENER
base-commit: 44f49511b7940adf3be4337d4feb2de38fe92297
--
2.49.0
--n6t6hie3zne7u6vd--
^ permalink raw reply [nested|flat] 157+ messages in thread
end of thread, other threads:[~2025-12-18 17:21 UTC | newest]
Thread overview: 157+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v13 05/18] Refactor to allow reindexing all index partitions at once.. Justin Pryzby <[email protected]>
2020-11-01 18:25 [PATCH v12 4/5] Refactor to allow reindexing all index partitions at once Justin Pryzby <[email protected]>
2025-12-18 17:21 [PATCH v1] Use open file description locks for data directory lockfile Dmitrii Dolgov <[email protected]>
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox