Re: How to reproduce serialization failure for a read only transaction. - Mailing list pgsql-hackers

From Florian Pflug
Subject Re: How to reproduce serialization failure for a read only transaction.
Date
Msg-id CDF9F17E-C6EF-4E2A-A027-6AF6CE8195BC@phlo.org
Whole thread Raw
In response to How to reproduce serialization failure for a read only transaction.  (AK <alkuzo@gmail.com>)
Responses Re: How to reproduce serialization failure for a read only transaction.
List pgsql-hackers
On Jan6, 2014, at 20:41 , AK <alkuzo@gmail.com> wrote:
> If two transactions both read and write, I can easily reproduce the
> following: "could not serialize access due to read/write dependencies among
> transactions". However, the 9.3 documentation says that "When relying on
> Serializable transactions to prevent anomalies, it is important that any
> data read from a permanent user table not be considered valid until the
> transaction which read it has successfully committed. This is true even for
> read-only transactions".
>
> I cannot have a read-only transaction fail because of serialization
> anomalies. Can someone show me a working example please?

A read-only transaction will abort due to a serialization failure if
observes a state of the database which doesn't exist in any serial transaction
schedule. Here's an example (default isolation level is assumed to be
serializable, of course)

W1: START TRANSACTION ISOLATION LEVEL SERIALIZABLE;
W1: UPDATE t SET count=count+1 WHERE id=1; -- (*2)
W1: SELECT data FROM t WHERE id=2;         -- (*1)
W2: START TRANSACTION ISOLATION LEVEL SERIALIZABLE;
W2: UPDATE t SET count=count+1 WHERE id=2; -- (*1, *2)
W2: COMMIT;
R : START TRANSACTION ISOLATION LEVEL SERIALIZABLE READ ONLY;
R : SELECT data FROM t WHERE id IN (1,2);  -- (*2)
W1: COMMIT; -- R will now report a serialization error!

Due to (*1), W1 must execute before W2 in any serial schedule, since W1
reads record 2 which is later modified by W2.

Due to (*2), R must execute after W2 but before W1 since it reads record
2 previously modified by W2 and record 1 later modified by W1. (Note that
W1 hasn't committed at time R acquires its snapshot)

The dependencies induced by (*1) or (*2) alone are satisfyable by a serial
schedule, but both together aren't - if W1 must execute before W2 as required
by (*1), then surely every transaction that runs after W2 in such a schedule
also runs after W1, thus contradicting (*2).

Now since (*1) alone isn't contradictory, committing W1 succeeds. That leaves
only the last line, the COMMIT of R, to fail, which it does.

The gist of this example is that whether the state observed by R exists in
any serial transaction schedule or not is only certain after all concurrent
read-write transactions (W1 and W2) have committed. You can avoid the error
above by specifying DEFERRABLE in R's START TRANSACTION command. The session
will then acquire a snapshot and wait for all possibly interfering read-write
transactions to commit. If the snapshot turns out to be observable in some
serial schedule, the session will continue, otherwise the database will
acquire a new snapshot and wait again. Thus, once the START TRANSACTION
with the DEFERRABLE flag has committed, you can be sure that the transaction
won't later be aborted due to a serialization error.

BTW, since this is a question about how to use postgres rather than
how to extend it, it actually belongs on pgsql-general, not on the hackers list.

best regards,
Florian Pflug




pgsql-hackers by date:

Previous
From: Robert Haas
Date:
Subject: Re: truncating pg_multixact/members
Next
From: Robert Haas
Date:
Subject: Re: Convert Datum* to char*