Skip to content

Commit 506c7e1

Browse files
michail-nikolaevCommitfest Bot
authored andcommitted
Track and drop auxiliary indexes in DROP/REINDEX
During concurrent index operations, auxiliary indexes may be left as orphaned objects when errors occur (junk auxiliary indexes). This patch improves the handling of such auxiliary indexes: - add auxiliaryForIndexId parameter to index_create() to track dependencies between main and auxiliary indexes - automatically drop auxiliary indexes when the main index is dropped - delete junk auxiliary indexes properly during REINDEX operations
1 parent e7e5b77 commit 506c7e1

File tree

14 files changed

+366
-41
lines changed

14 files changed

+366
-41
lines changed

doc/src/sgml/ref/create_index.sgml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -668,10 +668,16 @@ Indexes:
668668
"idx_ccaux" stir (col) INVALID
669669
</programlisting>
670670

671-
The recommended recovery
672-
method in such cases is to drop these indexes and try again to perform
673-
<command>CREATE INDEX CONCURRENTLY</command>. (Another possibility is
674-
to rebuild the index with <command>REINDEX INDEX CONCURRENTLY</command>).
671+
The recommended recovery method in such cases is to drop the index with
672+
<command>DROP INDEX</command>. The auxiliary index (suffixed with
673+
<literal>ccaux</literal>) will be automatically dropped when the main
674+
index is dropped. After dropping the indexes, you can try again to perform
675+
<command>CREATE INDEX CONCURRENTLY</command>. (Another possibility is to
676+
rebuild the index with <command>REINDEX INDEX CONCURRENTLY</command>,
677+
which will also handle cleanup of any invalid auxiliary indexes.)
678+
If the only invalid index is one suffixed <literal>ccaux</literal>
679+
recommended recovery method is just <literal>DROP INDEX</literal>
680+
for that index.
675681
</para>
676682

677683
<para>

doc/src/sgml/ref/reindex.sgml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -477,11 +477,15 @@ Indexes:
477477
<literal>_ccnew</literal> or <literal>_ccaux</literal>, then it corresponds to the transient or auxiliary
478478
index created during the concurrent operation, and the recommended
479479
recovery method is to drop these indexes using <literal>DROP INDEX</literal>,
480-
then attempt <command>REINDEX CONCURRENTLY</command> again.
480+
then attempt <command>REINDEX CONCURRENTLY</command> again. The auxiliary index
481+
(suffixed with <literal>_ccaux</literal>) will be automatically dropped
482+
along with its main index.
481483
If the invalid index is instead suffixed <literal>_ccold</literal>,
482484
it corresponds to the original index which could not be dropped;
483485
the recommended recovery method is to just drop said index, since the
484-
rebuild proper has been successful.
486+
rebuild proper has been successful. If the only
487+
invalid index is one suffixed <literal>ccaux</literal> recommended
488+
recovery method is just <literal>DROP INDEX</literal> for that index.
485489
A nonzero number may be appended to the suffix of the invalid index
486490
names to keep them unique, like <literal>_ccnew1</literal>,
487491
<literal>_ccold2</literal>, etc.

src/backend/catalog/dependency.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ performDeletion(const ObjectAddress *object,
286286
* Acquire deletion lock on the target object. (Ideally the caller has
287287
* done this already, but many places are sloppy about it.)
288288
*/
289-
AcquireDeletionLock(object, 0);
289+
AcquireDeletionLock(object, flags);
290290

291291
/*
292292
* Construct a list of objects to delete (ie, the given object plus

src/backend/catalog/index.c

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,8 @@ index_create(Relation heapRelation,
776776
((flags & INDEX_CREATE_ADD_CONSTRAINT) != 0));
777777
/* partitioned indexes must never be "built" by themselves */
778778
Assert(!partitioned || (flags & INDEX_CREATE_SKIP_BUILD));
779+
/* ii_AuxiliaryForIndexId and INDEX_CREATE_AUXILIARY are required both or neither */
780+
Assert(OidIsValid(indexInfo->ii_AuxiliaryForIndexId) == auxiliary);
779781

780782
relkind = partitioned ? RELKIND_PARTITIONED_INDEX : RELKIND_INDEX;
781783
is_exclusion = (indexInfo->ii_ExclusionOps != NULL);
@@ -1181,6 +1183,15 @@ index_create(Relation heapRelation,
11811183
recordDependencyOn(&myself, &referenced, DEPENDENCY_PARTITION_SEC);
11821184
}
11831185

1186+
/*
1187+
* Record dependency on the main index in case of auxiliary index.
1188+
*/
1189+
if (OidIsValid(indexInfo->ii_AuxiliaryForIndexId))
1190+
{
1191+
ObjectAddressSet(referenced, RelationRelationId, indexInfo->ii_AuxiliaryForIndexId);
1192+
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
1193+
}
1194+
11841195
/* placeholder for normal dependencies */
11851196
addrs = new_object_addresses();
11861197

@@ -1413,7 +1424,8 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId,
14131424
true,
14141425
indexRelation->rd_indam->amsummarizing,
14151426
oldInfo->ii_WithoutOverlaps,
1416-
false);
1427+
false,
1428+
InvalidOid);
14171429

14181430
/*
14191431
* Extract the list of column names and the column numbers for the new
@@ -1581,7 +1593,8 @@ index_concurrently_create_aux(Relation heapRelation, Oid mainIndexId,
15811593
true,
15821594
false, /* aux are not summarizing */
15831595
false, /* aux are not without overlaps */
1584-
true /* auxiliary */);
1596+
true /* auxiliary */,
1597+
mainIndexId /* auxiliaryForIndexId */);
15851598

15861599
/*
15871600
* Extract the list of column names and the column numbers for the new
@@ -2634,7 +2647,8 @@ BuildIndexInfo(Relation index)
26342647
false,
26352648
index->rd_indam->amsummarizing,
26362649
indexStruct->indisexclusion && indexStruct->indisunique,
2637-
index->rd_rel->relam == STIR_AM_OID /* auxiliary iff STIR */);
2650+
index->rd_rel->relam == STIR_AM_OID /* auxiliary iff STIR */,
2651+
InvalidOid /* auxiliary_for_index_id is set only during build */);
26382652

26392653
/* fill in attribute numbers */
26402654
for (i = 0; i < numAtts; i++)
@@ -2695,7 +2709,8 @@ BuildDummyIndexInfo(Relation index)
26952709
false,
26962710
index->rd_indam->amsummarizing,
26972711
indexStruct->indisexclusion && indexStruct->indisunique,
2698-
index->rd_rel->relam == STIR_AM_OID /* auxiliary iff STIR */);
2712+
index->rd_rel->relam == STIR_AM_OID /* auxiliary iff STIR */,
2713+
InvalidOid);
26992714

27002715
/* fill in attribute numbers */
27012716
for (i = 0; i < numAtts; i++)
@@ -3870,6 +3885,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
38703885
heapRelation;
38713886
Oid heapId;
38723887
Oid save_userid;
3888+
Oid junkAuxIndexId;
38733889
int save_sec_context;
38743890
int save_nestlevel;
38753891
IndexInfo *indexInfo;
@@ -3926,6 +3942,19 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
39263942
pgstat_progress_update_multi_param(2, progress_cols, progress_vals);
39273943
}
39283944

3945+
/* Check for the auxiliary index for that index, it needs to dropped */
3946+
junkAuxIndexId = get_auxiliary_index(indexId);
3947+
if (OidIsValid(junkAuxIndexId))
3948+
{
3949+
ObjectAddress object;
3950+
object.classId = RelationRelationId;
3951+
object.objectId = junkAuxIndexId;
3952+
object.objectSubId = 0;
3953+
performDeletion(&object, DROP_RESTRICT,
3954+
PERFORM_DELETION_INTERNAL |
3955+
PERFORM_DELETION_QUIETLY);
3956+
}
3957+
39293958
/*
39303959
* Open the target index relation and get an exclusive lock on it, to
39313960
* ensure that no one else is touching this particular index.
@@ -4214,7 +4243,8 @@ reindex_relation(const ReindexStmt *stmt, Oid relid, int flags,
42144243
{
42154244
Relation rel;
42164245
Oid toast_relid;
4217-
List *indexIds;
4246+
List *indexIds,
4247+
*auxIndexIds = NIL;
42184248
char persistence;
42194249
bool result = false;
42204250
ListCell *indexId;
@@ -4303,13 +4333,30 @@ reindex_relation(const ReindexStmt *stmt, Oid relid, int flags,
43034333
else
43044334
persistence = rel->rd_rel->relpersistence;
43054335

4336+
foreach(indexId, indexIds)
4337+
{
4338+
Oid indexOid = lfirst_oid(indexId);
4339+
Oid indexAm = get_rel_relam(indexOid);
4340+
4341+
/* All STIR indexes are auxiliary indexes */
4342+
if (indexAm == STIR_AM_OID)
4343+
{
4344+
if (flags & REINDEX_REL_SUPPRESS_INDEX_USE)
4345+
RemoveReindexPending(indexOid);
4346+
auxIndexIds = lappend_oid(auxIndexIds, indexOid);
4347+
}
4348+
}
4349+
43064350
/* Reindex all the indexes. */
43074351
i = 1;
43084352
foreach(indexId, indexIds)
43094353
{
43104354
Oid indexOid = lfirst_oid(indexId);
43114355
Oid indexNamespaceId = get_rel_namespace(indexOid);
4312-
Oid indexAm = get_rel_relam(indexOid);
4356+
4357+
/* Auxiliary indexes are going to be dropped during main index rebuild */
4358+
if (list_member_oid(auxIndexIds, indexOid))
4359+
continue;
43134360

43144361
/*
43154362
* Skip any invalid indexes on a TOAST table. These can only be
@@ -4335,18 +4382,6 @@ reindex_relation(const ReindexStmt *stmt, Oid relid, int flags,
43354382
continue;
43364383
}
43374384

4338-
if (indexAm == STIR_AM_OID)
4339-
{
4340-
ereport(WARNING,
4341-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4342-
errmsg("skipping reindex of auxiliary index \"%s.%s\"",
4343-
get_namespace_name(indexNamespaceId),
4344-
get_rel_name(indexOid))));
4345-
if (flags & REINDEX_REL_SUPPRESS_INDEX_USE)
4346-
RemoveReindexPending(indexOid);
4347-
continue;
4348-
}
4349-
43504385
reindex_index(stmt, indexOid, !(flags & REINDEX_REL_CHECK_CONSTRAINTS),
43514386
persistence, params);
43524387

src/backend/catalog/pg_depend.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,6 +1035,63 @@ get_index_constraint(Oid indexId)
10351035
return constraintId;
10361036
}
10371037

1038+
/*
1039+
* get_auxiliary_index
1040+
* Given the OID of an index, return the OID of its auxiliary
1041+
* index, or InvalidOid if there is no auxiliary index.
1042+
*/
1043+
Oid
1044+
get_auxiliary_index(Oid indexId)
1045+
{
1046+
Oid auxiliaryIndexOid = InvalidOid;
1047+
Relation depRel;
1048+
ScanKeyData key[3];
1049+
SysScanDesc scan;
1050+
HeapTuple tup;
1051+
1052+
/* Search the dependency table for the index */
1053+
depRel = table_open(DependRelationId, AccessShareLock);
1054+
1055+
ScanKeyInit(&key[0],
1056+
Anum_pg_depend_refclassid,
1057+
BTEqualStrategyNumber, F_OIDEQ,
1058+
ObjectIdGetDatum(RelationRelationId));
1059+
ScanKeyInit(&key[1],
1060+
Anum_pg_depend_refobjid,
1061+
BTEqualStrategyNumber, F_OIDEQ,
1062+
ObjectIdGetDatum(indexId));
1063+
ScanKeyInit(&key[2],
1064+
Anum_pg_depend_refobjsubid,
1065+
BTEqualStrategyNumber, F_INT4EQ,
1066+
Int32GetDatum(0));
1067+
1068+
scan = systable_beginscan(depRel, DependReferenceIndexId, true,
1069+
NULL, 3, key);
1070+
1071+
1072+
while (HeapTupleIsValid(tup = systable_getnext(scan)))
1073+
{
1074+
Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
1075+
1076+
/*
1077+
* We assume any AUTO dependency on index with rel_kind
1078+
* of RELKIND_INDEX is that we are looking for.
1079+
*/
1080+
if (deprec->classid == RelationRelationId &&
1081+
(deprec->deptype == DEPENDENCY_AUTO) &&
1082+
get_rel_relkind(deprec->objid) == RELKIND_INDEX)
1083+
{
1084+
auxiliaryIndexOid = deprec->objid;
1085+
break;
1086+
}
1087+
}
1088+
1089+
systable_endscan(scan);
1090+
table_close(depRel, AccessShareLock);
1091+
1092+
return auxiliaryIndexOid;
1093+
}
1094+
10381095
/*
10391096
* get_index_ref_constraints
10401097
* Given the OID of an index, return the OID of all foreign key

src/backend/catalog/toasting.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
308308
indexInfo->ii_Am = BTREE_AM_OID;
309309
indexInfo->ii_AmCache = NULL;
310310
indexInfo->ii_Auxiliary = false;
311+
indexInfo->ii_AuxiliaryForIndexId = InvalidOid;
311312
indexInfo->ii_Context = CurrentMemoryContext;
312313

313314
collationIds[0] = InvalidOid;

0 commit comments

Comments
 (0)