Thread: Re: Lock changes with 8.1 - what's the right lock?

Re: Lock changes with 8.1 - what's the right lock?

From
Wes
Date:
> Did you try the example I posted?  What happens if you do the
> following?  First set up a couple of tables:

I no longer have 7.4 running.  I'll have to check and see if can test.

> Is it possible that your foreign key constraints are DEFERRED in
> 7.4 but not in 8.1?  That would change transaction behavior that
> depends on locks.

No, there was no change to the database other than to start using table
spaces in 8.1.  Previously when multiple jobs were running concurrently,
they'd block while updating 'addresses', then take off and complete - unless
they hit a foreign key that someone else had referenced in which case they'd
block again.  Now one job waits at the initial addresses lock until the
other is completely done running (i.e. not updating tables that reference
addresses).

> An ordinary SELECT acquires ACCESS SHARE, which conflicts only with
> the strongest lock, ACCESS EXCLUSIVE.  If you're modifying a table
> that has a foreign key constraint then 8.1 does a SELECT FOR SHARE
> on the referenced table and earlier versions do a SELECT FOR UPDATE;
> both cases acquire ROW SHARE on the referenced table.  Two lock
> types are stronger than SHARE ROW EXCLUSIVE: EXCLUSIVE and ACCESS
> EXCLUSIVE, both of which conflict with ROW SHARE.  So instead of
> saying that SHARE ROW EXCLUSIVE is the weakest lock that meets your
> requirements, I should have said that it's the only lock that does.

That's what I thought from reading the manual, but wasn't sure.  Thanks.

I found the information that led me to believe the locking was fixed in 8.1.
The problem I had with 7.x was the 'deadlock detected' if the foreign keys
weren't referenced in sorted order, as the records were locked with more
than a share lock.

>> I haven't seen anything to indicate that 8.x improves foreign key
>> refererence locking and fixes the foreign key 'deadlock detected' issue.
>> Has that been addressed in 8.1?
>
> 8.1 should be using the new shared row locks for doing the checks.  This
> should fix the case mentioned.
>
>> I've never quite understood why a READ of a record with a foreign key
>> reference results in the referenced record being locked with more than a
>> shared lock.
>
> Up until now, we didn't have one to get on a per-record basis.

and

>> So, until 8.1 PostgreSQL had "something better than row-level locking" for
>> some things, but no row locking when needed?  Or was it row locking is
>> there, but just no shared row locking?
>
> The latter, the row locks before were single owner and were such that a
> second lock request for the same row would wait for the first to be
> released. Now effectively you have two levels of locks at the row level,
> the weaker of which conflicts with the stronger but not with itself. The
> thing about MVCC is that readers do not have to get either lock if they
> aren't trying to prevent modifications.


Wes



Re: Lock changes with 8.1 - what's the right lock?

From
Michael Fuhr
Date:
On Tue, Jul 25, 2006 at 07:12:28AM -0500, Wes wrote:
> > Unless I'm misunderstanding you or a bug was fixed between 7.4.5
> > and 7.4.13 (the version I'm running), I'm not convinced that last
> > statement is true.  EXCLUSIVE conflicts with all lock types except
> > ACCESS SHARE; foreign key references prior to 8.1 use SELECT FOR
> > UPDATE and in 8.1 they use SELECT FOR SHARE, but in both cases they
> > acquire ROW SHARE on the referenced table, which conflicts with
> > EXCLUSIVE.
>
> My apologies for being so unclear.  I had intended to just indicate that the
> problem occurred when we upgraded from 7.4.5 to 8.1, as opposed to this
> being fixed specifically in 8.1.  I didn't realize this was fixed in a 7.4
> release - I thought it was 8.x.  The last time I'd checked, it hadn't been
> fixed in 7.x.

New in 8.1 is that foreign key references use SELECT FOR SHARE
instead of SELECT FOR UPDATE, but in all versions the acquired locks
conflict with EXCLUSIVE.  I see nothing in the Release Notes
indicating that that behavior changed between 7.4.5 and 7.4.13.

Did you try the example I posted?  What happens if you do the
following?  First set up a couple of tables:

CREATE TABLE foo (id integer PRIMARY KEY);
CREATE TABLE bar (fooid integer NOT NULL REFERENCES foo);
INSERT INTO foo VALUES (1);

Then open two connections to the database and execute the steps in
T1 in one connection and then the steps in T2 in the other connection:

T1: BEGIN;
T1: INSERT INTO bar VALUES (1);

T2: BEGIN;
T2: LOCK TABLE foo IN EXCLUSIVE MODE;

The T2 connection should block until you execute COMMIT or ROLLBACK
in T1.  What happens on your system?  Does this approximate what
you're doing?

Is it possible that your foreign key constraints are DEFERRED in
7.4 but not in 8.1?  That would change transaction behavior that
depends on locks.

> > SHARE ROW EXCLUSIVE is the weakest lock that meets these requirements.
> > It conflicts with itself (#2) and with ROW EXCLUSIVE, which UPDATE,
> > DELETE, and INSERT acquire (#1), but doesn't conflict with ROW SHARE,
> > which is what SELECT FOR UPDATE/SHARE acquire (#3).
>
> Thanks for the confirmation.  Is there any stronger lock that would not
> block SELECT foreign key references?  I didn't find any documentation on
> what type of lock is grabbed by a when a foreign key is referenced during
> SELECT (or other).

An ordinary SELECT acquires ACCESS SHARE, which conflicts only with
the strongest lock, ACCESS EXCLUSIVE.  If you're modifying a table
that has a foreign key constraint then 8.1 does a SELECT FOR SHARE
on the referenced table and earlier versions do a SELECT FOR UPDATE;
both cases acquire ROW SHARE on the referenced table.  Two lock
types are stronger than SHARE ROW EXCLUSIVE: EXCLUSIVE and ACCESS
EXCLUSIVE, both of which conflict with ROW SHARE.  So instead of
saying that SHARE ROW EXCLUSIVE is the weakest lock that meets your
requirements, I should have said that it's the only lock that does.

Hopefully I've understood what you're asking; if not then please
clarify.

--
Michael Fuhr

Re: Lock changes with 8.1 - what's the right lock?

From
Wes
Date:
> Unless I'm misunderstanding you or a bug was fixed between 7.4.5
> and 7.4.13 (the version I'm running), I'm not convinced that last
> statement is true.  EXCLUSIVE conflicts with all lock types except
> ACCESS SHARE; foreign key references prior to 8.1 use SELECT FOR
> UPDATE and in 8.1 they use SELECT FOR SHARE, but in both cases they
> acquire ROW SHARE on the referenced table, which conflicts with
> EXCLUSIVE.

My apologies for being so unclear.  I had intended to just indicate that the
problem occurred when we upgraded from 7.4.5 to 8.1, as opposed to this
being fixed specifically in 8.1.  I didn't realize this was fixed in a 7.4
release - I thought it was 8.x.  The last time I'd checked, it hadn't been
fixed in 7.x.

>> What is now the appropriate lock?  It needs to:
>>
>>   1. Prevent others from updating the table
>>   2. Block other jobs that are requesting the same lock (if job 2 does a
>> SELECT and finds nothing, it will try to create the record that job 1 may
>> already have created in its transaction).
>>   3. Not conflict with foreign key reference locks
>
> SHARE ROW EXCLUSIVE is the weakest lock that meets these requirements.
> It conflicts with itself (#2) and with ROW EXCLUSIVE, which UPDATE,
> DELETE, and INSERT acquire (#1), but doesn't conflict with ROW SHARE,
> which is what SELECT FOR UPDATE/SHARE acquire (#3).

Thanks for the confirmation.  Is there any stronger lock that would not
block SELECT foreign key references?  I didn't find any documentation on
what type of lock is grabbed by a when a foreign key is referenced during
SELECT (or other).

Wes