Thread

  1. [PATCH 2/6] Refactor index_concurrently_create_copy() for use with REPACK (CONCURRENTLY).

    Antonin Houska <ah@cybertec.at> — 2025-12-13T18:27:18Z

    This patch moves the code to index_create_copy() and adds a "concurrently"
    parameter so it can be used by REPACK (CONCURRENTLY).
    
    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 system catalog entries) *before* the actual swap, to reduce the
    time AccessExclusiveLock needs to be held for.
    ---
     src/backend/catalog/index.c      | 54 +++++++++++++++++++++++---------
     src/backend/commands/cluster.c   |  8 ++---
     src/backend/commands/indexcmds.c |  6 ++--
     src/backend/nodes/makefuncs.c    |  9 +++---
     src/include/catalog/index.h      |  3 ++
     src/include/nodes/makefuncs.h    |  4 ++-
     6 files changed, 57 insertions(+), 27 deletions(-)
    
    diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
    index bd77584bc99..60efa77d34f 100644
    --- a/src/backend/catalog/index.c
    +++ b/src/backend/catalog/index.c
    @@ -1290,15 +1290,32 @@ index_create(Relation heapRelation,
     /*
      * index_concurrently_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.
    - *
    - * "tablespaceOid" is the tablespace to use for this index.
    + * Variant of index_create_copy(), called during concurrent reindex
    + * processing.
      */
     Oid
     index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId,
     							   Oid tablespaceOid, const char *newName)
    +{
    +	return index_create_copy(heapRelation, oldIndexId, tablespaceOid, newName,
    +							 true);
    +}
    +
    +/*
    + * index_create_copy
    + *
    + * 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.
    + *
    + * The actual implementation of index_concurrently_create_copy(), reusable for
    + * other purposes.
    + */
    +Oid
    +index_create_copy(Relation heapRelation, Oid oldIndexId, Oid tablespaceOid,
    +				  const char *newName, bool concurrently)
     {
     	Relation	indexRelation;
     	IndexInfo  *oldInfo,
    @@ -1317,6 +1334,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);
     
    @@ -1327,7 +1345,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")));
    @@ -1383,9 +1401,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,
    @@ -1394,10 +1410,13 @@ 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);
    +							oldInfo->ii_WithoutOverlaps,
    +							oldInfo->ii_ExclusionOps,
    +							oldInfo->ii_ExclusionProcs,
    +							oldInfo->ii_ExclusionStrats);
     
     	/*
     	 * Extract the list of column names and the column numbers for the new
    @@ -1435,6 +1454,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.
     	 *
    @@ -1458,7 +1480,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? */
    @@ -2452,7 +2474,8 @@ BuildIndexInfo(Relation index)
     					   indexStruct->indisready,
     					   false,
     					   index->rd_indam->amsummarizing,
    -					   indexStruct->indisexclusion && indexStruct->indisunique);
    +					   indexStruct->indisexclusion && indexStruct->indisunique,
    +					   NULL, NULL, NULL);
     
     	/* fill in attribute numbers */
     	for (i = 0; i < numAtts; i++)
    @@ -2512,7 +2535,8 @@ BuildDummyIndexInfo(Relation index)
     					   indexStruct->indisready,
     					   false,
     					   index->rd_indam->amsummarizing,
    -					   indexStruct->indisexclusion && indexStruct->indisunique);
    +					   indexStruct->indisexclusion && indexStruct->indisunique,
    +					   NULL, NULL, NULL);
     
     	/* fill in attribute numbers */
     	for (i = 0; i < numAtts; i++)
    diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
    index 7f772c5c4f8..a2d72ce494d 100644
    --- a/src/backend/commands/cluster.c
    +++ b/src/backend/commands/cluster.c
    @@ -70,8 +70,7 @@ typedef struct
     
     static bool cluster_rel_recheck(RepackCommand cmd, Relation OldHeap,
     								Oid indexOid, Oid userid, int options);
    -static void rebuild_relation(RepackCommand cmd,
    -							 Relation OldHeap, Relation index, bool verbose);
    +static void rebuild_relation(Relation OldHeap, Relation index, bool verbose);
     static void copy_table_data(Relation NewHeap, Relation OldHeap, Relation OldIndex,
     							bool verbose, bool *pSwapToastByContent,
     							TransactionId *pFreezeXid, MultiXactId *pCutoffMulti);
    @@ -415,7 +414,7 @@ cluster_rel(RepackCommand cmd, Relation OldHeap, Oid indexOid,
     	TransferPredicateLocksToHeapRelation(OldHeap);
     
     	/* rebuild_relation does all the dirty work */
    -	rebuild_relation(cmd, OldHeap, index, verbose);
    +	rebuild_relation(OldHeap, index, verbose);
     	/* rebuild_relation closes OldHeap, and index if valid */
     
     out:
    @@ -629,8 +628,7 @@ mark_index_clustered(Relation rel, Oid indexOid, bool is_internal)
      * On exit, they are closed, but locks on them are not released.
      */
     static void
    -rebuild_relation(RepackCommand cmd,
    -				 Relation OldHeap, Relation index, bool verbose)
    +rebuild_relation(Relation OldHeap, Relation index, bool verbose)
     {
     	Oid			tableOid = RelationGetRelid(OldHeap);
     	Oid			accessMethod = OldHeap->rd_rel->relam;
    diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
    index d9cccb6ac18..d8d8f72a875 100644
    --- a/src/backend/commands/indexcmds.c
    +++ b/src/backend/commands/indexcmds.c
    @@ -242,7 +242,8 @@ CheckIndexCompatible(Oid oldId,
     	 */
     	indexInfo = makeIndexInfo(numberOfAttributes, numberOfAttributes,
     							  accessMethodId, NIL, NIL, false, false,
    -							  false, false, amsummarizing, isWithoutOverlaps);
    +							  false, false, amsummarizing, isWithoutOverlaps,
    +							  NULL, NULL, NULL);
     	typeIds = palloc_array(Oid, numberOfAttributes);
     	collationIds = palloc_array(Oid, numberOfAttributes);
     	opclassIds = palloc_array(Oid, numberOfAttributes);
    @@ -927,7 +928,8 @@ DefineIndex(Oid tableId,
     							  !concurrent,
     							  concurrent,
     							  amissummarizing,
    -							  stmt->iswithoutoverlaps);
    +							  stmt->iswithoutoverlaps,
    +							  NULL, NULL, NULL);
     
     	typeIds = palloc_array(Oid, numberOfAttributes);
     	collationIds = palloc_array(Oid, numberOfAttributes);
    diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c
    index e2d9e9be41a..c5d5a37f514 100644
    --- a/src/backend/nodes/makefuncs.c
    +++ b/src/backend/nodes/makefuncs.c
    @@ -834,7 +834,8 @@ IndexInfo *
     makeIndexInfo(int numattrs, int numkeyattrs, Oid amoid, List *expressions,
     			  List *predicates, bool unique, bool nulls_not_distinct,
     			  bool isready, bool concurrent, bool summarizing,
    -			  bool withoutoverlaps)
    +			  bool withoutoverlaps, Oid *exclusion_ops, Oid *exclusion_procs,
    +			  uint16 *exclusion_strats)
     {
     	IndexInfo  *n = makeNode(IndexInfo);
     
    @@ -863,9 +864,9 @@ makeIndexInfo(int numattrs, int numkeyattrs, Oid amoid, List *expressions,
     	n->ii_PredicateState = NULL;
     
     	/* exclusion constraints */
    -	n->ii_ExclusionOps = NULL;
    -	n->ii_ExclusionProcs = NULL;
    -	n->ii_ExclusionStrats = NULL;
    +	n->ii_ExclusionOps = exclusion_ops;
    +	n->ii_ExclusionProcs = exclusion_procs;
    +	n->ii_ExclusionStrats = exclusion_strats;
     
     	/* speculative inserts */
     	n->ii_UniqueOps = NULL;
    diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
    index dda95e54903..4bf909078d8 100644
    --- a/src/include/catalog/index.h
    +++ b/src/include/catalog/index.h
    @@ -99,6 +99,9 @@ extern Oid	index_concurrently_create_copy(Relation heapRelation,
     										   Oid oldIndexId,
     										   Oid tablespaceOid,
     										   const char *newName);
    +extern Oid	index_create_copy(Relation heapRelation, Oid oldIndexId,
    +							  Oid tablespaceOid, const char *newName,
    +							  bool concurrently);
     
     extern void index_concurrently_build(Oid heapRelationId,
     									 Oid indexRelationId);
    diff --git a/src/include/nodes/makefuncs.h b/src/include/nodes/makefuncs.h
    index 5473ce9a288..9ff7159ff0c 100644
    --- a/src/include/nodes/makefuncs.h
    +++ b/src/include/nodes/makefuncs.h
    @@ -99,7 +99,9 @@ extern IndexInfo *makeIndexInfo(int numattrs, int numkeyattrs, Oid amoid,
     								List *expressions, List *predicates,
     								bool unique, bool nulls_not_distinct,
     								bool isready, bool concurrent,
    -								bool summarizing, bool withoutoverlaps);
    +								bool summarizing, bool withoutoverlaps,
    +								Oid *exclusion_ops, Oid *exclusion_procs,
    +								uint16 *exclusion_strats);
     
     extern Node *makeStringConst(char *str, int location);
     extern DefElem *makeDefElem(char *name, Node *arg, int location);
    -- 
    2.47.3
    
    
    --=-=-=
    Content-Type: text/x-diff
    Content-Disposition: attachment;
     filename=v28-0003-Move-conversion-of-a-historic-to-MVCC-snapshot-to-a-.patch