Re: More FOR UPDATE/FOR SHARE problems - Mailing list pgsql-hackers

From Bruce Momjian
Subject Re: More FOR UPDATE/FOR SHARE problems
Date
Msg-id 200902030129.n131Tso04572@momjian.us
Whole thread Raw
In response to Re: More FOR UPDATE/FOR SHARE problems  ("Kevin Grittner" <Kevin.Grittner@wicourts.gov>)
Responses Re: More FOR UPDATE/FOR SHARE problems
Re: More FOR UPDATE/FOR SHARE problems
List pgsql-hackers
Kevin Grittner wrote:
> >>> Tom Lane <tgl@sss.pgh.pa.us> wrote: 
> > Jeff Davis <pgsql@j-davis.com> writes:
> >> There you see a snapshot of the table that never existed. Either
> the
> >> snapshot was taken before the UPDATE, in which case i=3 should be
> >> included, or it was taken after the UPDATE, in which case i=4 should
> be
> >> included. So atomicity is broken for WHERE.
> > 
> > This assertion is based on a misunderstanding of what FOR UPDATE in
> > read-committed mode is defined to do.  It is supposed to give you
> the
> > latest available rows.
>  
> Well, technically it's violating the Isolation part of ACID, not the
> Atomicity, since the UPDATE transaction will either commit or roll
> back in its entirety, but another transaction can see it in an
> intermediate (partially applied) state.[1]
>  
> I guess the issue of whether this violation of ACID properties should
> be considered a bug or a feature is a separate discussion, but calling
> it a feature seems like a hard sell to me.

In trying to get some closure on this issue, I started investigating
this myself.  I realize there is the issue with serializable isolation
level that is already documented:
http://developer.postgresql.org/pgdocs/postgres/transaction-iso.html#XACT-SERIALIZABLE

Particularly, inserts by two transactions not seeing each other.  OK, at
least it is documented.

There is also the problem of queries that add and remove rows from
SELECT FOR UPDATE sets:
http://archives.postgresql.org/pgsql-hackers/2009-01/msg01803.php

I have come up with a simpler example of that behavior:
S1:test=> CREATE TABLE mvcc_test (status BOOLEAN);CREATE TABLEtest=> INSERT INTO mvcc_test VALUES (true),
(false);INSERT0 2test=> BEGIN;BEGINtest=> UPDATE mvcc_test SET status = NOT status;UPDATE 2S2:test=> SELECT * FROM
mvcc_testWHERE status = true FOR UPDATE;S1:test=> COMMIT;
 
S2: status--------(0 rows)

As you can see, the S2 SELECT FOR UPDATE returns zero rows, even though
one row would be returned before the UPDATE, and one row after the
update, and at no time were no rows matching its criteria ('true').

So, I thought, this is another SELECT FOR UPDATE problem, but then I was
able to duplicate it with just UPDATEs:

S1:test=> CREATE TABLE mvcc_test (status BOOLEAN);CREATE TABLEtest=> INSERT INTO mvcc_test VALUES (true),
(false);INSERT0 2test=> BEGIN;BEGINtest=> UPDATE mvcc_test SET status = NOT status;UPDATE 2S2:test=> UPDATE mvcc_test
SETstatus = true WHERE status = false;UPDATE 0S1:test=> COMMIT;
 
S2:test=> SELECT * FROM mvcc_test; status-------- t f(2 rows)

If the S2 UPDATE was run before or after the S1 UPDATE, it would have
set both rows to true, while you can see the two rows are different.

What is significant about this is that it isn't a serializable failure,
nor is it a SELECT FOR UPDATE failure.

The fundamental behavior above is that the S1 transaction is adding
_and_ removing rows from the S2 query's result set;  S2 is seeing the
pre-query values that don't match its criteria and ignoring them and
blocking on a later row that does match its criteria.  Once S1 commits,
the new row does not match its criteria and it skips it, making the
SELECT FOR UPDATE return zero rows, and the S2 UPDATE do nothing.

Serializable mode does prevent the problem outlined above.

Is this behavior documented already?  If not, where should I add it?
Perhaps section 13.2.1., "Read Committed Isolation Level":
http://developer.postgresql.org/pgdocs/postgres/transaction-iso.html#XACT-SERIALIZABLE

That section vaguely suggests this might happen but doesn't give an
example.

--  Bruce Momjian  <bruce@momjian.us>        http://momjian.us EnterpriseDB
http://enterprisedb.com
 + If your life is a hard drive, Christ can be your backup. +


pgsql-hackers by date:

Previous
From: KaiGai Kohei
Date:
Subject: Re: How to get SE-PostgreSQL acceptable
Next
From: Tom Lane
Date:
Subject: Re: [PATCHES] GIN improvements