Skip to content

Commit 4d21263

Browse files
committed
Heed lock protocol in DROP OWNED BY
We were acquiring object locks then deleting objects one by one, instead of acquiring all object locks first, ignoring those that did not exist, and then deleting all objects together. The latter is the correct protocol to use, and what this commits changes to code to do. Failing to follow that leads to "cache lookup failed for relation XYZ" error reports when DROP OWNED runs concurrently with other DDL -- for example, a session termination that removes some temp tables. Author: Álvaro Herrera Reported-by: Mithun Chicklore Yogendra (Mithun CY) Reviewed-by: Ahsan Hadi, Tom Lane Discussion: https://postgr.es/m/CADq3xVZTbzK4ZLKq+dn_vB4QafXXbmMgDP3trY-GuLnib2Ai1w@mail.gmail.com
1 parent 307ed98 commit 4d21263

File tree

4 files changed

+36
-8
lines changed

4 files changed

+36
-8
lines changed

src/backend/catalog/dependency.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,6 @@ static void reportDependentObjects(const ObjectAddresses *targetObjects,
191191
static void deleteOneObject(const ObjectAddress *object,
192192
Relation *depRel, int32 flags);
193193
static void doDeletion(const ObjectAddress *object, int flags);
194-
static void AcquireDeletionLock(const ObjectAddress *object, int flags);
195-
static void ReleaseDeletionLock(const ObjectAddress *object);
196194
static bool find_expr_references_walker(Node *node,
197195
find_expr_references_context *context);
198196
static void eliminate_duplicate_dependencies(ObjectAddresses *addrs);
@@ -1317,11 +1315,14 @@ doDeletion(const ObjectAddress *object, int flags)
13171315
/*
13181316
* AcquireDeletionLock - acquire a suitable lock for deleting an object
13191317
*
1318+
* Accepts the same flags as performDeletion (though currently only
1319+
* PERFORM_DELETION_CONCURRENTLY does anything).
1320+
*
13201321
* We use LockRelation for relations, LockDatabaseObject for everything
1321-
* else. Note that dependency.c is not concerned with deleting any kind of
1322-
* shared-across-databases object, so we have no need for LockSharedObject.
1322+
* else. Shared-across-databases objects are not currently supported
1323+
* because no caller cares, but could be modified to use LockSharedObject.
13231324
*/
1324-
static void
1325+
void
13251326
AcquireDeletionLock(const ObjectAddress *object, int flags)
13261327
{
13271328
if (object->classId == RelationRelationId)
@@ -1347,8 +1348,10 @@ AcquireDeletionLock(const ObjectAddress *object, int flags)
13471348

13481349
/*
13491350
* ReleaseDeletionLock - release an object deletion lock
1351+
*
1352+
* Companion to AcquireDeletionLock.
13501353
*/
1351-
static void
1354+
void
13521355
ReleaseDeletionLock(const ObjectAddress *object)
13531356
{
13541357
if (object->classId == RelationRelationId)

src/backend/catalog/pg_shdepend.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1240,14 +1240,29 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
12401240
sdepForm->objid);
12411241
break;
12421242
case SHARED_DEPENDENCY_POLICY:
1243-
/* If unable to remove role from policy, remove policy. */
1243+
/*
1244+
* Try to remove role from policy; if unable to, remove
1245+
* policy.
1246+
*/
12441247
if (!RemoveRoleFromObjectPolicy(roleid,
12451248
sdepForm->classid,
12461249
sdepForm->objid))
12471250
{
12481251
obj.classId = sdepForm->classid;
12491252
obj.objectId = sdepForm->objid;
12501253
obj.objectSubId = sdepForm->objsubid;
1254+
/*
1255+
* Acquire lock on object, then verify this dependency
1256+
* is still relevant. If not, the object might have
1257+
* been dropped or the policy modified. Ignore the
1258+
* object in that case.
1259+
*/
1260+
AcquireDeletionLock(&obj, 0);
1261+
if (!systable_recheck_tuple(scan, tuple))
1262+
{
1263+
ReleaseDeletionLock(&obj);
1264+
break;
1265+
}
12511266
add_exact_object_address(&obj, deleteobjs);
12521267
}
12531268
break;
@@ -1258,6 +1273,13 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
12581273
obj.classId = sdepForm->classid;
12591274
obj.objectId = sdepForm->objid;
12601275
obj.objectSubId = sdepForm->objsubid;
1276+
/* as above */
1277+
AcquireDeletionLock(&obj, 0);
1278+
if (!systable_recheck_tuple(scan, tuple))
1279+
{
1280+
ReleaseDeletionLock(&obj);
1281+
break;
1282+
}
12611283
add_exact_object_address(&obj, deleteobjs);
12621284
}
12631285
break;

src/backend/commands/subscriptioncmds.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -899,7 +899,6 @@ DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel)
899899
if (slotname)
900900
PreventTransactionChain(isTopLevel, "DROP SUBSCRIPTION");
901901

902-
903902
ObjectAddressSet(myself, SubscriptionRelationId, subid);
904903
EventTriggerSQLDropAddObject(&myself, true, true);
905904

src/include/catalog/dependency.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,10 @@ typedef enum ObjectClass
180180

181181
/* in dependency.c */
182182

183+
extern void AcquireDeletionLock(const ObjectAddress *object, int flags);
184+
185+
extern void ReleaseDeletionLock(const ObjectAddress *object);
186+
183187
extern void performDeletion(const ObjectAddress *object,
184188
DropBehavior behavior, int flags);
185189

0 commit comments

Comments
 (0)