Re: Avoid orphaned objects dependencies, take 3
Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
To: Robert Haas <robertmhaas@gmail.com>
Cc: Michael Paquier <michael@paquier.xyz>, Alexander Lakhin <exclusion@gmail.com>, pgsql-hackers@lists.postgresql.org, Tom Lane <tgl@sss.pgh.pa.us>
Date: 2024-06-14T07:54:52Z
Lists: pgsql-hackers
Hi,
On Thu, Jun 13, 2024 at 02:27:45PM -0400, Robert Haas wrote:
> On Thu, Jun 13, 2024 at 12:52 PM Bertrand Drouvot
> <bertranddrouvot.pg@gmail.com> wrote:
> > > > table_open(childRelId, ...) would lock any "ALTER TABLE <childRelId> DROP CONSTRAINT"
> > > > already. Not sure I understand your concern here.
> > >
> > > I believe this is not true. This would take a lock on the table, not
> > > the constraint itself.
> >
> > I agree that it would not lock the constraint itself. What I meant to say is that
> > , nevertheless, the constraint can not be dropped. Indeed, the "ALTER TABLE"
> > necessary to drop the constraint (ALTER TABLE <childRelId> DROP CONSTRAINT) would
> > be locked by the table_open(childRelId, ...).
>
> Ah, right. So, I was assuming that, with either this version of your
> patch or the earlier version, we'd end up locking the constraint
> itself. Was I wrong about that?
The child contraint itself is not locked when going through
ConstraintSetParentConstraint().
While at it, let's look at a full example and focus on your concern.
Let's do that with this gdb file:
"
$ cat gdb.txt
b dependency.c:1542
command 1
printf "Will return for: classId %d and objectId %d\n", object->classId, object->objectId
c
end
b dependency.c:1547 if object->classId == 2606
command 2
printf "Will lock constraint: classId %d and objectId %d\n", object->classId, object->objectId
c
end
"
knowing that:
"
Line 1542 is the return here in depLockAndCheckObject() (your concern):
if (object->classId == RelationRelationId || object->classId == AuthMemRelationId)
return;
Line 1547 is the lock here in depLockAndCheckObject():
/* assume we should lock the whole object not a sub-object */
LockDatabaseObject(object->classId, object->objectId, 0, AccessShareLock);
"
So, with gdb attached to a session let's:
1. Create the parent relation
CREATE TABLE upsert_test (
a INT,
b TEXT
) PARTITION BY LIST (a);
gdb produces:
---
Will return for: classId 1259 and objectId 16384
Will return for: classId 1259 and objectId 16384
---
Oid 16384 is upsert_test, so I think the return (dependency.c:1542) is fine as
we are creating the object (it can't be dropped as not visible to anyone else).
2. Create another relation (will be the child)
CREATE TABLE upsert_test_2 (b TEXT, a int);
gdb produces:
---
Will return for: classId 1259 and objectId 16391
Will return for: classId 1259 and objectId 16394
Will return for: classId 1259 and objectId 16394
Will return for: classId 1259 and objectId 16391
---
Oid 16391 is upsert_test_2
Oid 16394 is pg_toast_16391
so I think the return (dependency.c:1542) is fine as we are creating those
objects (can't be dropped as not visible to anyone else).
3. Attach the partition
ALTER TABLE upsert_test ATTACH PARTITION upsert_test_2 FOR VALUES IN (2);
gdb produces:
---
Will return for: classId 1259 and objectId 16384
---
That's fine because we'd already had locked the relation 16384 through
AlterTableLookupRelation()->RangeVarGetRelidExtended()->LockRelationOid().
4. Add a constraint on the child relation
ALTER TABLE upsert_test_2 add constraint bdtc2 UNIQUE (a);
gdb produces:
---
Will return for: classId 1259 and objectId 16391
Will lock constraint: classId 2606 and objectId 16397
---
That's fine because we'd already had locked the relation 16391 through
AlterTableLookupRelation()->RangeVarGetRelidExtended()->LockRelationOid().
Oid 16397 is the constraint we're creating (bdtc2).
5. Add a constraint on the parent relation (this goes through
ConstraintSetParentConstraint())
ALTER TABLE upsert_test add constraint bdtc1 UNIQUE (a);
gdb produces:
---
Will return for: classId 1259 and objectId 16384
Will lock constraint: classId 2606 and objectId 16399
Will return for: classId 1259 and objectId 16398
Will return for: classId 1259 and objectId 16391
Will lock constraint: classId 2606 and objectId 16399
Will return for: classId 1259 and objectId 16391
---
Regarding "Will return for: classId 1259 and objectId 16384":
That's fine because we'd already had locked the relation 16384 through
AlterTableLookupRelation()->RangeVarGetRelidExtended()->LockRelationOid().
Regarding "Will lock constraint: classId 2606 and objectId 16399":
Oid 16399 is the constraint that we're creating.
Regarding "Will return for: classId 1259 and objectId 16398":
That's fine because Oid 16398 is an index that we're creating while creating
the constraint (so the index can't be dropped as not visible to anyone else).
Regarding "Will return for: classId 1259 and objectId 16391":
That's fine because 16384 we'd be already locked (as mentioned above). And
I think that's fine because trying to drop "upsert_test_2" (aka 16391) would produce
RemoveRelations()->RangeVarGetRelidExtended()->RangeVarCallbackForDropRelation()
->LockRelationOid(relid=16384, lockmode=8) and so would be locked.
Regarding this example, I don't think that the return in depLockAndCheckObject():
"
if (object->classId == RelationRelationId || object->classId == AuthMemRelationId)
return;
"
is an issue. Indeed, the example above shows it would return for an object that
we'd be creating (so not visible to anyone else) or for an object that we'd
already have locked.
Is it an issue outside of this example?: I've the feeling it's not as we're
already careful when we deal with relations. That said, to be on the safe side
we could get rid of this return and make use of LockRelationOid() instead.
Regards,
--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com
Commits
Same data as JSON:
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
Avoid orphaned objects dependencies
- 2fbb21170e90 19 (unreleased) landed
- 5100bdbd3ba2 14 (unreleased) landed
- 5fa137727db0 15 (unreleased) landed
- d9bc0d96c247 16 (unreleased) landed
- 3a9909eda207 17 (unreleased) landed
- c8cd3d6976f7 18 (unreleased) landed
-
Don't try to record dependency on a dropped column's datatype
- fd93ee100830 19 (unreleased) landed
- 36b6ed2606e1 14 (unreleased) landed
- ef3d7b15e4cd 15 (unreleased) landed
- d44cd467471c 16 (unreleased) landed
- c1588f92a915 17 (unreleased) landed
- f9d5a52da4ca 18 (unreleased) landed