Thread: Fwd: question on foreign key lock

Fwd: question on foreign key lock

From
Filip Rembiałkowski
Date:
Hi,<br /><br />maybe this is a better group for this question?<br /><br />I can't see why creating foreign key on table
Areferencing table B, generates an AccessExclusiveLock on B.<br />It seems (to a layman :-) ) that only writes to B
shouldbe blocked.<br /><br />I'm really interested if this is either expected effect or any open TODO item or
suboptimalbehavior of postgres.<br /><br />Thanks<br /><br /><br /><div class="gmail_quote">---------- Forwarded
message----------<br />From: <b class="gmail_sendername">Filip Rembiałkowski</b> <span dir="ltr"><<a
href="mailto:filip.rembialkowski@gmail.com">filip.rembialkowski@gmail.com</a>></span><br/> Date: Thu, Nov 1, 2012 at
5:33PM<br />Subject: question on foreign key lock<br />To: pgsql-general list <<a
href="mailto:pgsql-general@postgresql.org">pgsql-general@postgresql.org</a>><br/><br /><br />Hello.<br /><br /> Why
addingFK creates AccessExclusiveLock on referenced tabble?<br /><br /> {{{<br /> CREATE TABLE A ( id integer, idb
integer);<br /> INSERT INTO A (id,idb) SELECT x, x%4 FROM generate_series(1,100) x;<br /><br /> CREATE TABLE B ( id int
primarykey );<br /> INSERT INTO B VALUES (0),(1),(2),(3);<br /><br /> BEGIN;<br /> ALTER TABLE A ADD CONSTRAINT
a_idb_fkeyFOREIGN KEY (idb) REFERENCES b;<br /> SELECT * FROM pg_locks l, pg_class c WHERE l.pid = pg_backend_pid() AND
l.locktype='relation'AND l.mode ilike '%exclusive%' AND l.relation=c.oid;<br /> ROLLBACK;<br /> }}}<br /><br /><br />
LastSELECT is showing AccessExclusive on B.<br /> Why not Exclusive?<br /><br /><br /> Thanks,<br /> Filip<br
/></div><br/> 

Re: Fwd: question on foreign key lock

From
Robert Haas
Date:
On Thu, Nov 8, 2012 at 3:45 AM, Filip Rembiałkowski
<filip.rembialkowski@gmail.com> wrote:
> maybe this is a better group for this question?
>
> I can't see why creating foreign key on table A referencing table B,
> generates an AccessExclusiveLock on B.
> It seems (to a layman :-) ) that only writes to B should be blocked.
>
> I'm really interested if this is either expected effect or any open TODO
> item or suboptimal behavior of postgres.

This comment explains it:
   /*    * Grab an exclusive lock on the pk table, so that someone doesn't delete    * rows out from under us.
(Althougha lesser lock would do for that    * purpose, we'll need exclusive lock anyway to add triggers to the pk    *
table;trying to start with a lesser lock will just create a risk of    * deadlock.)    */   pkrel =
heap_openrv(fkconstraint->pktable,AccessExclusiveLock); 

Concurrent DDL is something that's been discussed in detail on this
list in the past; unfortunately, there are some tricky race conditions
are the shared invalidation queue and SnapshotNow that make it hard to
implement properly.  I'm hoping to have some time to work on this at
some point, but it hasn't happened yet.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company



Re: Fwd: question on foreign key lock

From
Filip Rembiałkowski
Date:
Robert, thank you for  the answer.

1. "need exclusive lock anyway to add triggers".
Why adding a trigger needs exclusive lock?
Someone would say blocking reads is not needed (since possible trigger
events are: Insert/Update/Delete/Truncate).

2. "will create a risk of deadlock".
From user perspective a risk of deadlock is sometimes better than
excessive  locking. Transactional DDL users should be prepared for
exceptions/retries anyway.

3. I made a naive test of simply changing AccessExclusiveLock to
ExclusiveLock, and seeing how many regression tests it breaks. It
breaks none :-)
Current Git head gives me 2 fails/133 tests regardless of this change.


regards,
Filip










On Mon, Nov 12, 2012 at 5:20 PM, Robert Haas <robertmhaas@gmail.com> wrote:
> On Thu, Nov 8, 2012 at 3:45 AM, Filip Rembiałkowski
> <filip.rembialkowski@gmail.com> wrote:
>> maybe this is a better group for this question?
>>
>> I can't see why creating foreign key on table A referencing table B,
>> generates an AccessExclusiveLock on B.
>> It seems (to a layman :-) ) that only writes to B should be blocked.
>>
>> I'm really interested if this is either expected effect or any open TODO
>> item or suboptimal behavior of postgres.
>
> This comment explains it:
>
>     /*
>      * Grab an exclusive lock on the pk table, so that someone doesn't delete
>      * rows out from under us. (Although a lesser lock would do for that
>      * purpose, we'll need exclusive lock anyway to add triggers to the pk
>      * table; trying to start with a lesser lock will just create a risk of
>      * deadlock.)
>      */
>     pkrel = heap_openrv(fkconstraint->pktable, AccessExclusiveLock);
>
> Concurrent DDL is something that's been discussed in detail on this
> list in the past; unfortunately, there are some tricky race conditions
> are the shared invalidation queue and SnapshotNow that make it hard to
> implement properly.  I'm hoping to have some time to work on this at
> some point, but it hasn't happened yet.
>
> --
> Robert Haas
> EnterpriseDB: http://www.enterprisedb.com
> The Enterprise PostgreSQL Company



Re: Fwd: question on foreign key lock

From
Robert Haas
Date:
On Wed, Dec 5, 2012 at 7:08 AM, Filip Rembiałkowski
<filip.rembialkowski@gmail.com> wrote:
> Robert, thank you for  the answer.
>
> 1. "need exclusive lock anyway to add triggers".
> Why adding a trigger needs exclusive lock?
> Someone would say blocking reads is not needed (since possible trigger
> events are: Insert/Update/Delete/Truncate).
>
> 2. "will create a risk of deadlock".
> From user perspective a risk of deadlock is sometimes better than
> excessive  locking. Transactional DDL users should be prepared for
> exceptions/retries anyway.
>
> 3. I made a naive test of simply changing AccessExclusiveLock to
> ExclusiveLock, and seeing how many regression tests it breaks. It
> breaks none :-)
> Current Git head gives me 2 fails/133 tests regardless of this change.

Sure.  You could probably downgrade it quite a bit further without
breaking the regression tests, but that doesn't mean it's safe in all
cases.  Rather than having this discussion all over again, I suggest
that you have a look at commits
2dbbda02e7e688311e161a912a0ce00cde9bb6fc,
2c3d9db56d5d49bdc777b174982251c01348e3d8,
a195e3c34f1eeb6a607c342121edf48e49067ea9, and the various mailing list
discussions pertaining thereto, particularly the thread "ALTER TABLE
lock strength reduction patch is unsafe" which was started by Tom
Lane.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company



Re: Fwd: question on foreign key lock

From
Andres Freund
Date:
On 2012-12-05 17:05:41 -0500, Robert Haas wrote:
> On Wed, Dec 5, 2012 at 7:08 AM, Filip Rembiałkowski
> <filip.rembialkowski@gmail.com> wrote:
> > Robert, thank you for  the answer.
> >
> > 1. "need exclusive lock anyway to add triggers".
> > Why adding a trigger needs exclusive lock?
> > Someone would say blocking reads is not needed (since possible trigger
> > events are: Insert/Update/Delete/Truncate).
> >
> > 2. "will create a risk of deadlock".
> > From user perspective a risk of deadlock is sometimes better than
> > excessive  locking. Transactional DDL users should be prepared for
> > exceptions/retries anyway.
> >
> > 3. I made a naive test of simply changing AccessExclusiveLock to
> > ExclusiveLock, and seeing how many regression tests it breaks. It
> > breaks none :-)
> > Current Git head gives me 2 fails/133 tests regardless of this change.
>
> Sure.  You could probably downgrade it quite a bit further without
> breaking the regression tests, but that doesn't mean it's safe in all
> cases.  Rather than having this discussion all over again, I suggest
> that you have a look at commits
> 2dbbda02e7e688311e161a912a0ce00cde9bb6fc,
> 2c3d9db56d5d49bdc777b174982251c01348e3d8,
> a195e3c34f1eeb6a607c342121edf48e49067ea9, and the various mailing list
> discussions pertaining thereto, particularly the thread "ALTER TABLE
> lock strength reduction patch is unsafe" which was started by Tom
> Lane.

Just to give an example about the complexities surrounding this:
Lowering the lock level for foreign key creation probably would be
dangerous for query planning more precisely join removal.

S1: BEGIN TRANSACTION ISOLATION LEVEL REPATABLE READ;
S1: SELECT * FROM a;

S2: DELETE FROM a WHERE a.id IN (all_duplicate_ids);
S2: ALTER TABLE a ADD CONTSTRAINT a_unique UNIQUE (a);
S2: ALTER TABLE b ADD CONSTRAINT b_fkey FOREIGN KEY (b_id) REFERENCES a(id));

S1: SELECT b.id FROM a LEFT JOIN b ON(b.id = a.id);

The last S1 query might now remove the join to b because of the foreign
key (which it sees due to SnapshotNow semantics) although rows that
violate unique key (which is required for the foreign key) still
exist. The existance of those duplicate values would change the result
though!


(come to think of it, I think we might still hit the above case if S1
doesn't access a before the foreign key gets altered...)

Greetings,

Andres Freund

--Andres Freund                       http://www.2ndQuadrant.com/PostgreSQL Development, 24x7 Support, Training &
Services



Re: Fwd: question on foreign key lock

From
Tom Lane
Date:
Robert Haas <robertmhaas@gmail.com> writes:
> On Wed, Dec 5, 2012 at 7:08 AM, Filip Rembiałkowski
> <filip.rembialkowski@gmail.com> wrote:
>> 3. I made a naive test of simply changing AccessExclusiveLock to
>> ExclusiveLock, and seeing how many regression tests it breaks. It
>> breaks none :-)

> Sure.  You could probably downgrade it quite a bit further without
> breaking the regression tests, but that doesn't mean it's safe in all
> cases.

In fact, since the regression tests make no attempt whatsoever to stress
DDL executed concurrently with table accesses, it doesn't prove a darn
thing.  The standard regression tests actually try quite hard to avoid
such scenarios, so that the results will be repeatable.  You could
perhaps build relevant test cases using the isolationtester
infrastructure, but I don't think anyone has tried particularly.
        regards, tom lane