diff --git a/doc/src/sgml/ref/reindex.sgml b/doc/src/sgml/ref/reindex.sgml
index ee22c267c1..b0983c7ea1 100644
--- a/doc/src/sgml/ref/reindex.sgml
+++ b/doc/src/sgml/ref/reindex.sgml
@@ -386,9 +386,10 @@ Indexes:
The recommended recovery method in such cases is to drop the invalid
index and try again to perform REINDEX CONCURRENTLY.
The concurrent index created during the processing has a name ending in
- the suffix ccnew, or ccold if it is an old index definition which we failed
- to drop. Invalid indexes can be dropped using DROP INDEX,
- including invalid toast indexes.
+ the suffix ccnew, or ccold if it
+ is an old index definition which we failed to drop. Invalid indexes can
+ be dropped using DROP INDEX, including invalid toast
+ indexes.
@@ -396,9 +397,9 @@ Indexes:
table to occur in parallel, but only one concurrent index build can
occur on a table at a time. In both cases, no other types of schema
modification on the table are allowed meanwhile. Another difference
- is that a regular REINDEX TABLE or REINDEX INDEX
- command can be performed within a transaction block, but
- REINDEX CONCURRENTLY cannot.
+ is that a regular REINDEX TABLE or
+ REINDEX INDEX command can be performed within a
+ transaction block, but REINDEX CONCURRENTLY cannot.
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9b3a742663..b84c05736f 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -693,7 +693,6 @@ UpdateIndexRelation(Oid indexoid,
* classObjectId: array of index opclass OIDs, one per index column
* coloptions: array of per-index-column indoption settings
* reloptions: AM-specific options
- * tupdesc: Tuple descriptor used for the index if defined
* flags: bitmask that can include any combination of these bits:
* INDEX_CREATE_IS_PRIMARY
* the index is a primary key
@@ -734,7 +733,6 @@ index_create(Relation heapRelation,
Oid *classObjectId,
int16 *coloptions,
Datum reloptions,
- TupleDesc tupdesc,
bits16 flags,
bits16 constr_flags,
bool allow_system_table_mods,
@@ -742,6 +740,7 @@ index_create(Relation heapRelation,
Oid *constraintId)
{
Oid heapRelationId = RelationGetRelid(heapRelation);
+ Oid heapNamespaceId = get_rel_namespace(heapRelationId);
Relation pg_class;
Relation indexRelation;
TupleDesc indexTupDesc;
@@ -794,10 +793,12 @@ index_create(Relation heapRelation,
/*
* concurrent index build on a system catalog is unsafe because we tend to
- * release locks before committing in catalogs
+ * release locks before committing in catalogs. Toast catalogs are fine
+ * though as they are associated with a root relation which could be
+ * reindexed concurrently.
*/
if (concurrent &&
- IsSystemNamespace(get_rel_namespace(heapRelationId)))
+ IsSystemNamespace(heapNamespaceId))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("concurrent index creation on system catalog tables is not supported")));
@@ -865,20 +866,14 @@ index_create(Relation heapRelation,
}
/*
- * construct tuple descriptor for index tuples if not passed by caller
+ * construct tuple descriptor for index tuples
*/
- if (!tupdesc)
- indexTupDesc = ConstructTupleDescriptor(heapRelation,
- indexInfo,
- indexColNames,
- accessMethodObjectId,
- collationObjectId,
- classObjectId);
- else
- {
- Assert(indexColNames == NIL);
- indexTupDesc = tupdesc;
- }
+ indexTupDesc = ConstructTupleDescriptor(heapRelation,
+ indexInfo,
+ indexColNames,
+ accessMethodObjectId,
+ collationObjectId,
+ classObjectId);
/*
* Allocate an OID for the index, unless we were told what to use.
@@ -1210,14 +1205,15 @@ index_create(Relation heapRelation,
}
/*
- * index_concurrently_create_copy
+ * index_create_copy_concurrent
*
* Create concurrently an index based on the definition of the one provided by
* caller. The index is inserted into catalogs and needs to be built later
* on. This is called during concurrent reindex processing.
*/
Oid
-index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, const char *newName)
+index_create_copy_concurrent(Relation heapRelation, Oid oldIndexId,
+ const char *newName)
{
Relation indexRelation;
IndexInfo *indexInfo;
@@ -1231,6 +1227,8 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, const char
oidvector *indclass;
int2vector *indcoloptions;
bool isnull;
+ List *indexColNames = NIL;
+ int i;
indexRelation = index_open(oldIndexId, RowExclusiveLock);
@@ -1242,9 +1240,6 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, const char
indexInfo->ii_ExclusionProcs = NULL;
indexInfo->ii_ExclusionStrats = NULL;
- /* Create a copy of the tuple descriptor to be used for the new entry */
- indexTupDesc = CreateTupleDescCopyConstr(RelationGetDescr(indexRelation));
-
/* Get the array of class and column options IDs from index info */
indexTuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(oldIndexId));
if (!HeapTupleIsValid(indexTuple))
@@ -1266,6 +1261,19 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, const char
optionDatum = SysCacheGetAttr(RELOID, classTuple,
Anum_pg_class_reloptions, &isnull);
+ /*
+ * Extract the list of column names to be used for the index
+ * creation.
+ */
+ indexTupDesc = RelationGetDescr(indexRelation);
+ for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
+ {
+ Form_pg_attribute att = TupleDescAttr(indexTupDesc, i);
+
+ /* Grab the column name and save it to the list */
+ indexColNames = lappend(indexColNames, NameStr(att->attname));
+ }
+
/* Now create the new index */
newIndexId = index_create(heapRelation,
newName,
@@ -1274,14 +1282,13 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, const char
InvalidOid, /* parentConstraintId */
InvalidOid, /* relFileNode */
indexInfo,
- NIL,
+ indexColNames,
indexRelation->rd_rel->relam,
indexRelation->rd_rel->reltablespace,
indexRelation->rd_indcollation,
indclass->values,
indcoloptions->values,
optionDatum,
- indexTupDesc,
INDEX_CREATE_SKIP_BUILD | INDEX_CREATE_CONCURRENT,
0,
true, /* allow table to be a system catalog? */
@@ -1297,20 +1304,24 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, const char
}
/*
- * index_concurrently_build
+ * index_build_concurrent
*
* Build index for a concurrent operation. Low-level locks are taken when
- * this operation is performed to prevent only schema changes, but they need to
- * be kept until the end of the transaction performing this operation.
+ * this operation is performed to prevent only schema changes, but they need
+ * to be kept until the end of the transaction performing this operation.
+ * 'indexOid' refers to an index relation OID already created as part of
+ * previous processing, and 'heapOid' refers to its parent heap relation.
*/
void
-index_concurrently_build(Oid heapOid,
- Oid indexOid)
+index_build_concurrent(Oid heapOid, Oid indexOid)
{
Relation heapRel,
indexRelation;
IndexInfo *indexInfo;
+ /* This had better make sure that a snapshot is active */
+ Assert(ActiveSnapshotSet());
+
/* Open and lock the parent heap relation */
heapRel = table_open(heapOid, ShareUpdateExclusiveLock);
@@ -1344,13 +1355,13 @@ index_concurrently_build(Oid heapOid,
}
/*
- * index_concurrently_swap
+ * index_swap_concurrent
*
* Swap name, dependencies, and constraints of the old index over to the new
* index, while marking the old index as invalid and the new as valid.
*/
void
-index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName)
+index_swap_concurrent(Oid newIndexId, Oid oldIndexId, const char *oldName)
{
Relation pg_class,
pg_index,
@@ -1417,8 +1428,8 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName)
newIndexForm = (Form_pg_index) GETSTRUCT(newIndexTuple);
/*
- * Copy constraint flags for old index. This is safe because the old index
- * guaranteed uniqueness.
+ * Copy conntraint flags from the old index. This is safe because the old
+ * index guaranteed uniqueness.
*/
newIndexForm->indisprimary = oldIndexForm->indisprimary;
oldIndexForm->indisprimary = false;
@@ -1509,7 +1520,7 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName)
}
/*
- * Move comment if any
+ * Move comment if any.
*/
{
Relation description;
@@ -1555,7 +1566,7 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName)
}
/*
- * Move all dependencies on the old index to the new
+ * Move all dependencies on the old index to the new one.
*/
if (OidIsValid(indexConstraintOid))
@@ -1592,7 +1603,7 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName)
}
/*
- * index_concurrently_set_dead
+ * index_set_dead_concurrent
*
* Perform the last invalidation stage of DROP INDEX CONCURRENTLY or REINDEX
* CONCURRENTLY before actually dropping the index. After calling this
@@ -1601,7 +1612,7 @@ index_concurrently_swap(Oid newIndexId, Oid oldIndexId, const char *oldName)
* function.
*/
void
-index_concurrently_set_dead(Oid heapOid, Oid indexOid)
+index_set_dead_concurrent(Oid heapOid, Oid indexOid)
{
Relation heapRelation,
indexRelation;
@@ -1638,7 +1649,7 @@ index_concurrently_set_dead(Oid heapOid, Oid indexOid)
}
/*
- * index_concurrently_drop
+ * index_drop_concurrent
*
* Drop a single index concurrently as the last step of an index concurrent
* process. Deletion is done through performDeletion or dependencies of the
@@ -1648,7 +1659,7 @@ index_concurrently_set_dead(Oid heapOid, Oid indexOid)
* server sessions.
*/
void
-index_concurrently_drop(Oid indexId)
+index_drop_concurrent(Oid indexId)
{
Oid constraintOid = get_index_constraint(indexId);
ObjectAddress object;
@@ -2089,7 +2100,7 @@ index_drop(Oid indexId, bool concurrent)
WaitForLockers(heaplocktag, AccessExclusiveLock);
/* Finish invalidation of index and mark it as dead */
- index_concurrently_set_dead(heapId, indexId);
+ index_set_dead_concurrent(heapId, indexId);
/*
* Again, commit the transaction to make the pg_index update visible
diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c
index 969b34e752..b5b8f62b19 100644
--- a/src/backend/catalog/pg_depend.c
+++ b/src/backend/catalog/pg_depend.c
@@ -395,7 +395,7 @@ changeDependenciesOn(Oid refClassId, Oid oldRefObjectId,
ObjectAddress objAddr;
bool newIsPinned;
- depRel = heap_open(DependRelationId, RowExclusiveLock);
+ depRel = table_open(DependRelationId, RowExclusiveLock);
/*
* If oldRefObjectId is pinned, there won't be any dependency entries on
@@ -838,7 +838,7 @@ get_index_ref_constraints(Oid indexId)
HeapTuple tup;
/* Search the dependency table for the index */
- depRel = heap_open(DependRelationId, AccessShareLock);
+ depRel = table_open(DependRelationId, AccessShareLock);
ScanKeyInit(&key[0],
Anum_pg_depend_refclassid,
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index fb93c41c88..77be19175a 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -336,7 +336,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
list_make2("chunk_id", "chunk_seq"),
BTREE_AM_OID,
rel->rd_rel->reltablespace,
- collationObjectId, classObjectId, coloptions, (Datum) 0, NULL,
+ collationObjectId, classObjectId, coloptions, (Datum) 0,
INDEX_CREATE_IS_PRIMARY, 0, true, true, NULL);
table_close(toast_rel, NoLock);
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index a3b6aed0a7..8a80308c3b 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -305,15 +305,15 @@ CheckIndexCompatible(Oid oldId,
* Wait for transactions that might have an older snapshot than the given xmin
* limit, because it might not contain tuples deleted just before it has
* been taken. Obtain a list of VXIDs of such transactions, and wait for them
- * individually.
+ * individually. This is used when building concurrently an index.
*
* We can exclude any running transactions that have xmin > the xmin given;
* their oldest snapshot must be newer than our xmin limit.
* We can also exclude any transactions that have xmin = zero, since they
* evidently have no live snapshot at all (and any one they might be in
* process of taking is certainly newer than ours). Transactions in other
- * DBs can be ignored too, since they'll never even be able to see this
- * index.
+ * DBs can be ignored too, since they'll never even be able to see the
+ * index worked on.
*
* We can also exclude autovacuum processes and processes running manual
* lazy VACUUMs, because they won't be fazed by missing index entries
@@ -937,7 +937,7 @@ DefineIndex(Oid relationId,
stmt->oldNode, indexInfo, indexColNames,
accessMethodId, tablespaceId,
collationObjectId, classObjectId,
- coloptions, reloptions, NULL,
+ coloptions, reloptions,
flags, constr_flags,
allowSystemTableMods, !check_rights,
&createdConstraintId);
@@ -1237,10 +1237,7 @@ DefineIndex(Oid relationId,
PushActiveSnapshot(GetTransactionSnapshot());
/* Perform concurrent build of index */
- index_concurrently_build(RangeVarGetRelid(stmt->relation,
- ShareUpdateExclusiveLock,
- false),
- indexRelationId);
+ index_build_concurrent(relationId, indexRelationId);
/* we can do away with our snapshot */
PopActiveSnapshot();
@@ -2814,9 +2811,9 @@ ReindexRelationConcurrently(Oid relationOid, int options)
false);
/* Create new index definition based on given index */
- concurrentOid = index_concurrently_create_copy(indexParentRel,
- indOid,
- concurrentName);
+ concurrentOid = index_create_copy_concurrent(indexParentRel,
+ indOid,
+ concurrentName);
/* Now open the relation of the new index, a lock is also needed on it */
indexConcurrentRel = index_open(concurrentOid, ShareUpdateExclusiveLock);
@@ -2851,7 +2848,8 @@ ReindexRelationConcurrently(Oid relationOid, int options)
*/
foreach(lc, parentRelationIds)
{
- Relation heapRelation = table_open(lfirst_oid(lc), ShareUpdateExclusiveLock);
+ Relation heapRelation = table_open(lfirst_oid(lc),
+ ShareUpdateExclusiveLock);
LockRelId lockrelid = heapRelation->rd_lockInfo.lockRelId;
LOCKTAG *heaplocktag;
@@ -2914,7 +2912,6 @@ ReindexRelationConcurrently(Oid relationOid, int options)
Relation indexRel;
Oid indOid = lfirst_oid(lc);
Oid concurrentOid = lfirst_oid(lc2);
- Oid tableOid;
CHECK_FOR_INTERRUPTS();
@@ -2926,14 +2923,15 @@ ReindexRelationConcurrently(Oid relationOid, int options)
/*
* Index relation has been closed by previous commit, so reopen it to
- * get its information.
+ * determine if it is used as a primary key.
*/
indexRel = index_open(indOid, ShareUpdateExclusiveLock);
- tableOid = indexRel->rd_index->indrelid;
- index_close(indexRel, NoLock);
/* Perform concurrent build of new index */
- index_concurrently_build(tableOid, concurrentOid);
+ index_build_concurrent(indexRel->rd_index->indrelid, concurrentOid);
+
+ /* Keep lock until the end of this transaction */
+ index_close(indexRel, NoLock);
/* We can do away with our snapshot */
PopActiveSnapshot();
@@ -3045,7 +3043,7 @@ ReindexRelationConcurrently(Oid relationOid, int options)
false);
/* Swap old index with the new one */
- index_concurrently_swap(concurrentOid, indOid, oldName);
+ index_swap_concurrent(concurrentOid, indOid, oldName);
/*
* Invalidate the relcache for the table, so that after this commit
@@ -3090,7 +3088,7 @@ ReindexRelationConcurrently(Oid relationOid, int options)
relOid = IndexGetRelation(indOid, false);
/* Finish the index invalidation and set it as dead. */
- index_concurrently_set_dead(relOid, indOid);
+ index_set_dead_concurrent(relOid, indOid);
}
/* Commit this transaction to make the updates visible. */
@@ -3118,14 +3116,14 @@ ReindexRelationConcurrently(Oid relationOid, int options)
CHECK_FOR_INTERRUPTS();
- index_concurrently_drop(indOid);
+ index_drop_concurrent(indOid);
}
PopActiveSnapshot();
CommitTransactionCommand();
/*
- * Finallt release the session-level lock on the parent table.
+ * Finally release the session-level lock on the parent table.
*/
foreach(lc, relationLocks)
{
diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index 84dd900dd6..803fa6a2c8 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -65,7 +65,6 @@ extern Oid index_create(Relation heapRelation,
Oid *classObjectId,
int16 *coloptions,
Datum reloptions,
- TupleDesc tupdesc,
bits16 flags,
bits16 constr_flags,
bool allow_system_table_mods,
@@ -78,22 +77,6 @@ extern Oid index_create(Relation heapRelation,
#define INDEX_CONSTR_CREATE_UPDATE_INDEX (1 << 3)
#define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS (1 << 4)
-extern Oid index_concurrently_create_copy(Relation heapRelation,
- Oid oldIndexId,
- const char *newName);
-
-extern void index_concurrently_build(Oid heapOid,
- Oid indexOid);
-
-extern void index_concurrently_swap(Oid newIndexId,
- Oid oldIndexId,
- const char *oldName);
-
-extern void index_concurrently_set_dead(Oid heapOid,
- Oid indexOid);
-
-extern void index_concurrently_drop(Oid indexId);
-
extern ObjectAddress index_constraint_create(Relation heapRelation,
Oid indexRelationId,
Oid parentConstraintId,
@@ -127,6 +110,21 @@ extern void index_build(Relation heapRelation,
bool isreindex,
bool parallel);
+extern void index_build_concurrent(Oid heapOid, Oid indexOid);
+
+extern Oid index_create_copy_concurrent(Relation heapRelation,
+ Oid oldIndexId,
+ const char *newName);
+
+extern void index_swap_concurrent(Oid newIndexId,
+ Oid oldIndexId,
+ const char *oldName);
+
+extern void index_set_dead_concurrent(Oid heapOid,
+ Oid indexOid);
+
+extern void index_drop_concurrent(Oid indexId);
+
extern double IndexBuildHeapScan(Relation heapRelation,
Relation indexRelation,
IndexInfo *indexInfo,