Make index_concurrently_create_copy more general

Also rename it to index_create_copy.  Add a 'boolean concurrent' option,
and make it work for both cases: in concurrent mode, just create the
catalog entries; caller is responsible for the actual building later.
In non-concurrent mode, the index is built right away.

This allows it to be reused for other purposes -- specifically, for
concurrent REPACK.

(With the CONCURRENTLY option, REPACK cannot simply swap the heap file and
rebuild its indexes.  Instead, it needs to build a separate set of
indexes, including their system catalog entries, *before* the actual
swap, to reduce the time AccessExclusiveLock needs to be held for.  This
approach is different from what CREATE INDEX CONCURRENTLY does.)

Per a suggestion from Mihail Nikalayeu.

Author: Antonin Houska <ah@cybertec.at>
Reviewed-by: Mihail Nikalayeu <mihailnikalayeu@gmail.com>
Reviewed-by: Álvaro Herrera <alvherre@kurilemu.de>
Discussion: https://postgr.es/m/41104.1754922120@localhost
This commit is contained in:
Álvaro Herrera 2026-04-04 20:38:26 +02:00
parent 2d3490dd99
commit 33bf7318f9
No known key found for this signature in database
GPG key ID: 1C20ACB9D5C564AE
3 changed files with 36 additions and 21 deletions

View file

@ -1289,17 +1289,17 @@ index_create(Relation heapRelation,
}
/*
* index_concurrently_create_copy
* index_create_copy
*
* 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.
* Create an index based on the definition of the one provided by caller. The
* index is inserted into catalogs. If 'concurrently' is TRUE, it needs to be
* built later on; otherwise it's built immediately.
*
* "tablespaceOid" is the tablespace to use for this index.
*/
Oid
index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId,
Oid tablespaceOid, const char *newName)
index_create_copy(Relation heapRelation, bool concurrently,
Oid oldIndexId, Oid tablespaceOid, const char *newName)
{
Relation indexRelation;
IndexInfo *oldInfo,
@ -1318,6 +1318,7 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId,
List *indexColNames = NIL;
List *indexExprs = NIL;
List *indexPreds = NIL;
int flags = 0;
indexRelation = index_open(oldIndexId, RowExclusiveLock);
@ -1328,7 +1329,7 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId,
* Concurrent build of an index with exclusion constraints is not
* supported.
*/
if (oldInfo->ii_ExclusionOps != NULL)
if (oldInfo->ii_ExclusionOps != NULL && concurrently)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("concurrent index creation for exclusion constraints is not supported")));
@ -1384,9 +1385,7 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId,
}
/*
* Build the index information for the new index. Note that rebuild of
* indexes with exclusion constraints is not supported, hence there is no
* need to fill all the ii_Exclusion* fields.
* Build the index information for the new index.
*/
newInfo = makeIndexInfo(oldInfo->ii_NumIndexAttrs,
oldInfo->ii_NumIndexKeyAttrs,
@ -1395,11 +1394,24 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId,
indexPreds,
oldInfo->ii_Unique,
oldInfo->ii_NullsNotDistinct,
false, /* not ready for inserts */
true,
!concurrently, /* isready */
concurrently, /* concurrent */
indexRelation->rd_indam->amsummarizing,
oldInfo->ii_WithoutOverlaps);
/* fetch exclusion constraint info if any */
if (indexRelation->rd_index->indisexclusion)
{
/*
* XXX Beware: we're making newInfo point to oldInfo-owned memory. It
* would be more orthodox to palloc+memcpy, but we don't need that
* here at present.
*/
newInfo->ii_ExclusionOps = oldInfo->ii_ExclusionOps;
newInfo->ii_ExclusionProcs = oldInfo->ii_ExclusionProcs;
newInfo->ii_ExclusionStrats = oldInfo->ii_ExclusionStrats;
}
/*
* Extract the list of column names and the column numbers for the new
* index information. All this information will be used for the index
@ -1436,6 +1448,9 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId,
stattargets[i].isnull = isnull;
}
if (concurrently)
flags = INDEX_CREATE_SKIP_BUILD | INDEX_CREATE_CONCURRENT;
/*
* Now create the new index.
*
@ -1459,7 +1474,7 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId,
indcoloptions->values,
stattargets,
reloptionsDatum,
INDEX_CREATE_SKIP_BUILD | INDEX_CREATE_CONCURRENT,
flags,
0,
true, /* allow table to be a system catalog? */
false, /* is_internal? */

View file

@ -3989,10 +3989,11 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein
tablespaceid = indexRel->rd_rel->reltablespace;
/* Create new index definition based on given index */
newIndexId = index_concurrently_create_copy(heapRel,
idx->indexId,
tablespaceid,
concurrentName);
newIndexId = index_create_copy(heapRel,
true,
idx->indexId,
tablespaceid,
concurrentName);
/*
* Now open the relation of the new index, a session-level lock is

View file

@ -101,10 +101,9 @@ extern Oid index_create(Relation heapRelation,
#define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS (1 << 4)
#define INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS (1 << 5)
extern Oid index_concurrently_create_copy(Relation heapRelation,
Oid oldIndexId,
Oid tablespaceOid,
const char *newName);
extern Oid index_create_copy(Relation heapRelation, bool concurrently,
Oid oldIndexId, Oid tablespaceOid,
const char *newName);
extern void index_concurrently_build(Oid heapRelationId,
Oid indexRelationId);