> > 1. Tx Old is running.
> > 2. Tx S reads new transaction ID in GetSnapshotData() and swapped away
> > before SInval acquired.
> > 3. Tx New gets new transaction ID, makes changes and commits.
> > 4. Tx Old changes some row R changed by Tx New and commits.
> > 5. Tx S gets snapshot data and now sees R changed by *both* Tx Old and
> > Tx New *but* does not see *other* changes made by Tx New =>
> > Tx S reads unconsistent data.
>
> Hmm, but that doesn't seem to have anything to do with the way that
> GetSnapshotData operates. If Tx New has an XID >= xmax read by Tx S'
> GetSnapshotData, then Tx New will be considered uncommitted by S no
> matter which order we get the locks in; it hardly matters whether Tx New
You forget about Tx Old! The point is that changes made by Tx Old *over*
Tx New' changes effectively make those Tx New' changes *visible* to
Tx S!
And this is not good: Tx New inserts PK and corresponding FK and commits;
Tx Old changes some field in row with that FK and commits - now Tx S will
see
FK row *but not PK one* (and what if Tx S was serializable Tx run by
pd_dump...)
SInval lock prevents Tx Old from commit (xact.c:CommitTransaction()) in
points 2. - 4. above and so Tx Old' changes will not be visible to Tx S.
> manages to physically commit before we finish building the snapshot for
> S. On the other side of the coin, if Tx New's XID < xmax for S, then
> *with the GetNewTransactionId change that I want* we can be sure that
> Tx New will be seen running by S when it does get the SInval lock
> (unless New has managed to finish before S gets the lock, in which case
> it's perfectly reasonable for S to treat it as committed or aborted).
And this is how it worked (MyProc->xid was updated while holding
XXXGenLockId) in varsup.c from version 1.21 (Jun 1999) till
version 1.36 (Mar 2001) when you occasionally moved it outside
of locked code part:
http://www.ca.postgresql.org/cgi/cvsweb.cgi/pgsql/src/backend/access/transam
/varsup.c.diff?r1=1.35&r2=1.36
> Anyway, it seems to me that the possibility of inconsistent data is
> inherent in the way we handle updated rows in Read Committed mode ---
> you can always get to see a row that was emitted by a transaction you
> don't see the other effects of.
If I correctly understand meaning of "emitted" then sentence above is not
correct:
set of rows to be updated can only be shortened by concurrent transactions.
Yes, changes can be made over changes from concurrent transactions but only
for rows from original set defined by query snapshot and only if
concurrently
updated rows (from that set) satisfy query qual => a row must satisfy
snapshot
*and* query qual = double satisfaction guaranteed -:))
And let's remember that this behaviour is required for current RI
constraints
implementation.
Vadim