Skip to content

Commit e31d524

Browse files
committed
Fix intermittent crash in DROP INDEX CONCURRENTLY.
When deleteOneObject closes and reopens the pg_depend relation, we must see to it that the relcache pointer held by the calling function (typically performMultipleDeletions) is updated. Usually the relcache entry is retained so that the pointer value doesn't change, which is why the problem had escaped notice ... but after a cache flush event there's no guarantee that the same memory will be reassigned. To fix, change the recursive functions' APIs so that we pass around a "Relation *" not just "Relation". Per investigation of occasional buildfarm failures. This is trivial to reproduce with -DCLOBBER_CACHE_ALWAYS, which points up the sad lack of any buildfarm member running that way on a regular basis.
1 parent 5e15cdb commit e31d524

File tree

1 file changed

+22
-22
lines changed

1 file changed

+22
-22
lines changed

src/backend/catalog/dependency.c

+22-22
Original file line numberDiff line numberDiff line change
@@ -171,13 +171,13 @@ static void findDependentObjects(const ObjectAddress *object,
171171
ObjectAddressStack *stack,
172172
ObjectAddresses *targetObjects,
173173
const ObjectAddresses *pendingObjects,
174-
Relation depRel);
174+
Relation *depRel);
175175
static void reportDependentObjects(const ObjectAddresses *targetObjects,
176176
DropBehavior behavior,
177177
int msglevel,
178178
const ObjectAddress *origObject);
179179
static void deleteOneObject(const ObjectAddress *object,
180-
Relation depRel, int32 flags);
180+
Relation *depRel, int32 flags);
181181
static void doDeletion(const ObjectAddress *object, int flags);
182182
static void AcquireDeletionLock(const ObjectAddress *object, int flags);
183183
static void ReleaseDeletionLock(const ObjectAddress *object);
@@ -250,7 +250,7 @@ performDeletion(const ObjectAddress *object,
250250
NULL, /* empty stack */
251251
targetObjects,
252252
NULL, /* no pendingObjects */
253-
depRel);
253+
&depRel);
254254

255255
/*
256256
* Check if deletion is allowed, and report about cascaded deletes.
@@ -267,7 +267,7 @@ performDeletion(const ObjectAddress *object,
267267
{
268268
ObjectAddress *thisobj = targetObjects->refs + i;
269269

270-
deleteOneObject(thisobj, depRel, flags);
270+
deleteOneObject(thisobj, &depRel, flags);
271271
}
272272

273273
/* And clean up */
@@ -328,7 +328,7 @@ performMultipleDeletions(const ObjectAddresses *objects,
328328
NULL, /* empty stack */
329329
targetObjects,
330330
objects,
331-
depRel);
331+
&depRel);
332332
}
333333

334334
/*
@@ -349,7 +349,7 @@ performMultipleDeletions(const ObjectAddresses *objects,
349349
{
350350
ObjectAddress *thisobj = targetObjects->refs + i;
351351

352-
deleteOneObject(thisobj, depRel, flags);
352+
deleteOneObject(thisobj, &depRel, flags);
353353
}
354354

355355
/* And clean up */
@@ -398,7 +398,7 @@ deleteWhatDependsOn(const ObjectAddress *object,
398398
NULL, /* empty stack */
399399
targetObjects,
400400
NULL, /* no pendingObjects */
401-
depRel);
401+
&depRel);
402402

403403
/*
404404
* Check if deletion is allowed, and report about cascaded deletes.
@@ -427,7 +427,7 @@ deleteWhatDependsOn(const ObjectAddress *object,
427427
* action. If, in the future, this function is used for other
428428
* purposes, we might need to revisit this.
429429
*/
430-
deleteOneObject(thisobj, depRel, PERFORM_DELETION_INTERNAL);
430+
deleteOneObject(thisobj, &depRel, PERFORM_DELETION_INTERNAL);
431431
}
432432

433433
/* And clean up */
@@ -462,15 +462,15 @@ deleteWhatDependsOn(const ObjectAddress *object,
462462
* targetObjects: list of objects that are scheduled to be deleted
463463
* pendingObjects: list of other objects slated for destruction, but
464464
* not necessarily in targetObjects yet (can be NULL if none)
465-
* depRel: already opened pg_depend relation
465+
* *depRel: already opened pg_depend relation
466466
*/
467467
static void
468468
findDependentObjects(const ObjectAddress *object,
469469
int flags,
470470
ObjectAddressStack *stack,
471471
ObjectAddresses *targetObjects,
472472
const ObjectAddresses *pendingObjects,
473-
Relation depRel)
473+
Relation *depRel)
474474
{
475475
ScanKeyData key[3];
476476
int nkeys;
@@ -540,7 +540,7 @@ findDependentObjects(const ObjectAddress *object,
540540
else
541541
nkeys = 2;
542542

543-
scan = systable_beginscan(depRel, DependDependerIndexId, true,
543+
scan = systable_beginscan(*depRel, DependDependerIndexId, true,
544544
SnapshotNow, nkeys, key);
545545

546546
while (HeapTupleIsValid(tup = systable_getnext(scan)))
@@ -715,7 +715,7 @@ findDependentObjects(const ObjectAddress *object,
715715
else
716716
nkeys = 2;
717717

718-
scan = systable_beginscan(depRel, DependReferenceIndexId, true,
718+
scan = systable_beginscan(*depRel, DependReferenceIndexId, true,
719719
SnapshotNow, nkeys, key);
720720

721721
while (HeapTupleIsValid(tup = systable_getnext(scan)))
@@ -986,10 +986,10 @@ reportDependentObjects(const ObjectAddresses *targetObjects,
986986
/*
987987
* deleteOneObject: delete a single object for performDeletion.
988988
*
989-
* depRel is the already-open pg_depend relation.
989+
* *depRel is the already-open pg_depend relation.
990990
*/
991991
static void
992-
deleteOneObject(const ObjectAddress *object, Relation depRel, int flags)
992+
deleteOneObject(const ObjectAddress *object, Relation *depRel, int flags)
993993
{
994994
ScanKeyData key[3];
995995
int nkeys;
@@ -1012,7 +1012,7 @@ deleteOneObject(const ObjectAddress *object, Relation depRel, int flags)
10121012
* relation open across doDeletion().
10131013
*/
10141014
if (flags & PERFORM_DELETION_CONCURRENTLY)
1015-
heap_close(depRel, RowExclusiveLock);
1015+
heap_close(*depRel, RowExclusiveLock);
10161016

10171017
/*
10181018
* Delete the object itself, in an object-type-dependent way.
@@ -1029,7 +1029,7 @@ deleteOneObject(const ObjectAddress *object, Relation depRel, int flags)
10291029
* Reopen depRel if we closed it above
10301030
*/
10311031
if (flags & PERFORM_DELETION_CONCURRENTLY)
1032-
depRel = heap_open(DependRelationId, RowExclusiveLock);
1032+
*depRel = heap_open(DependRelationId, RowExclusiveLock);
10331033

10341034
/*
10351035
* Now remove any pg_depend records that link from this object to others.
@@ -1057,12 +1057,12 @@ deleteOneObject(const ObjectAddress *object, Relation depRel, int flags)
10571057
else
10581058
nkeys = 2;
10591059

1060-
scan = systable_beginscan(depRel, DependDependerIndexId, true,
1060+
scan = systable_beginscan(*depRel, DependDependerIndexId, true,
10611061
SnapshotNow, nkeys, key);
10621062

10631063
while (HeapTupleIsValid(tup = systable_getnext(scan)))
10641064
{
1065-
simple_heap_delete(depRel, &tup->t_self);
1065+
simple_heap_delete(*depRel, &tup->t_self);
10661066
}
10671067

10681068
systable_endscan(scan);
@@ -1125,10 +1125,6 @@ doDeletion(const ObjectAddress *object, int flags)
11251125
break;
11261126
}
11271127

1128-
case OCLASS_EVENT_TRIGGER:
1129-
RemoveEventTriggerById(object->objectId);
1130-
break;
1131-
11321128
case OCLASS_PROC:
11331129
RemoveFunctionById(object->objectId);
11341130
break;
@@ -1238,6 +1234,10 @@ doDeletion(const ObjectAddress *object, int flags)
12381234
RemoveExtensionById(object->objectId);
12391235
break;
12401236

1237+
case OCLASS_EVENT_TRIGGER:
1238+
RemoveEventTriggerById(object->objectId);
1239+
break;
1240+
12411241
default:
12421242
elog(ERROR, "unrecognized object class: %u",
12431243
object->classId);

0 commit comments

Comments
 (0)