Обсуждение: Tuple visibility within a single XID

Поиск
Список
Период
Сортировка

Tuple visibility within a single XID

От
Jim Nasby
Дата:
My understanding is that all subtransactions get their own unique XID 
(assuming they need one), and that CommandId can't move backwards within 
a transaction. If that's correct, then shouldn't we be able to prune 
tuples where XMIN and XMAX match our *exact* XID (not all the extra 
stuff that TransactionIdIsCurrentTransactionId() does) and CommandId < 
CurrentCommandId?

I thought of this because of a post to -general. It's certainly not a 
common case, but it seems like there's not much downside...
-- 
Jim Nasby, Data Architect, Blue Treble Consulting
Data in Trouble? Get it in Treble! http://BlueTreble.com



Re: Tuple visibility within a single XID

От
Peter Geoghegan
Дата:
On Tue, Apr 7, 2015 at 5:59 PM, Jim Nasby <Jim.Nasby@bluetreble.com> wrote:
> My understanding is that all subtransactions get their own unique XID
> (assuming they need one), and that CommandId can't move backwards within a
> transaction. If that's correct, then shouldn't we be able to prune tuples
> where XMIN and XMAX match our *exact* XID (not all the extra stuff that
> TransactionIdIsCurrentTransactionId() does) and CommandId <
> CurrentCommandId?

No. For one thing, unique index enforcement still requires the tuples
to be treated as a conflict while the other transaction is running
IMV.

For another, this is necessary today (from ExecUpdate()):

/*
* The target tuple was already updated or deleted by the
* current command, or by a later command in the current
* transaction.  The former case is possible in a join UPDATE
* where multiple tuples join to the same target tuple. This
* is pretty questionable, but Postgres has always allowed it:
* we just execute the first update action and ignore
* additional update attempts.
*
* The latter case arises if the tuple is modified by a
* command in a BEFORE trigger, or perhaps by a command in a
* volatile function used in the query.  In such situations we
* should not ignore the update, but it is equally unsafe to
* proceed.  We don't want to discard the original UPDATE
* while keeping the triggered actions based on it; and we
* have no principled way to merge this update with the
* previous ones.  So throwing an error is the only safe
* course.
*
* If a trigger actually intends this type of interaction, it
* can re-execute the UPDATE (assuming it can figure out how)
* and then return NULL to cancel the outer update.
*/
if (hufd.cmax != estate->es_output_cid)
ereport(ERROR,            (errcode(ERRCODE_TRIGGERED_DATA_CHANGE_VIOLATION),             errmsg("tuple to be updated
wasalready modified by an
 
operation triggered by the current command"),             errhint("Consider using an AFTER trigger instead of a
BEFORE trigger to propagate changes to other rows.")));


You're not the first to consider trying something like this in
specific scenarios, but my work on UPSERT leads me to believe it isn't
workable.
-- 
Peter Geoghegan



Re: Tuple visibility within a single XID

От
Jim Nasby
Дата:
On 4/7/15 8:11 PM, Peter Geoghegan wrote:
> You're not the first to consider trying something like this in
> specific scenarios, but my work on UPSERT leads me to believe it isn't
> workable.

Yeah, every time I get into the really nitty-gritty details of this 
stuff it gets scary. That's why I didn't even bother with a patch before 
asking.

Thanks for setting me straight. :)
-- 
Jim Nasby, Data Architect, Blue Treble Consulting
Data in Trouble? Get it in Treble! http://BlueTreble.com



Re: Tuple visibility within a single XID

От
Qingqing Zhou
Дата:
On Tue, Apr 7, 2015 at 6:11 PM, Peter Geoghegan <pg@heroku.com> wrote:
> No. For one thing, unique index enforcement still requires the tuples
> to be treated as a conflict while the other transaction is running
> IMV.
>

Not sure if I understand correctly: in uniqueness check, we see all
possible tuples with a dirty snapshot.  For a tuple version inserted
and updated by myself, it is surely dead no matter how the transaction
ends. So I interpret that we can safely pruning the version.

Early pruning may cause some behavior change though. For example, here is a T1:

begin;  -- loop the following statements many times  insert into pk values (1);  -- uniqueness defined  delete from
pk;
abort;

If another transaction T2 coming later than T1, and if we prune early,
then T1 can suddenly hang on insertion waiting for T2 to complete. But
does this violate any isolation rule?
Thanks,
Qingqing



Re: Tuple visibility within a single XID

От
Peter Geoghegan
Дата:
On Tue, Apr 7, 2015 at 7:16 PM, Qingqing Zhou <zhouqq.postgres@gmail.com> wrote:
> If another transaction T2 coming later than T1, and if we prune early,
> then T1 can suddenly hang on insertion waiting for T2 to complete. But
> does this violate any isolation rule?

Well, it means that you don't lock a row that you delete (and values
that appeared in that row if they're constrained by a unique index)
just because you happened to also insert that row. That would probably
break client code.

-- 
Peter Geoghegan



Re: Tuple visibility within a single XID

От
Tom Lane
Дата:
Qingqing Zhou <zhouqq.postgres@gmail.com> writes:
> Not sure if I understand correctly: in uniqueness check, we see all
> possible tuples with a dirty snapshot.  For a tuple version inserted
> and updated by myself, it is surely dead no matter how the transaction
> ends. So I interpret that we can safely pruning the version.

It may be dead in the future, but unless you can prove that your session
does not still contain a snapshot that could "see" the row, you can't
prune it.  Considering only the current query is a fundamental error.
        regards, tom lane