Thread: Tuples inserted and deleted by the same transaction

Tuples inserted and deleted by the same transaction

From
Laurenz Albe
Date:
Shouldn't such tuples be considered dead right away, even if the inserting
transaction is still active?  That would allow cleaning them up even before
the transaction is done.

There is this code in HeapTupleSatisfiesVacuumHorizon:

        else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
        {
            [...]
            /* inserted and then deleted by same xact */
            if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetUpdateXid(tuple)))
                return HEAPTUPLE_DELETE_IN_PROGRESS;

Why HEAPTUPLE_DELETE_IN_PROGRESS and not HEAPTUPLE_DEAD?

Yours,
Laurenz Albe



Re: Tuples inserted and deleted by the same transaction

From
Nikita Malakhov
Date:
Hi!

Please correct me if I'm wrong, despite tuples being inserted and deleted by the same 
transaction - they are visible inside the transaction and usable by it, so considering them
dead and cleaning up during execution is a bad idea until the transaction is ended.

On Tue, Sep 13, 2022 at 11:06 AM Laurenz Albe <laurenz.albe@cybertec.at> wrote:
Shouldn't such tuples be considered dead right away, even if the inserting
transaction is still active?  That would allow cleaning them up even before
the transaction is done.

There is this code in HeapTupleSatisfiesVacuumHorizon:

        else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
        {
            [...]
            /* inserted and then deleted by same xact */
            if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetUpdateXid(tuple)))
                return HEAPTUPLE_DELETE_IN_PROGRESS;

Why HEAPTUPLE_DELETE_IN_PROGRESS and not HEAPTUPLE_DEAD?

Yours,
Laurenz Albe


--
Regards,
Nikita Malakhov
Postgres Professional 

Re: Tuples inserted and deleted by the same transaction

From
Laurenz Albe
Date:
On Tue, 2022-09-13 at 11:47 +0300, Nikita Malakhov wrote:
> On Tue, Sep 13, 2022 at 11:06 AM Laurenz Albe <laurenz.albe@cybertec.at> wrote:
> > Shouldn't such tuples be considered dead right away, even if the inserting
> > transaction is still active?  That would allow cleaning them up even before
> > the transaction is done.
> > 
> > There is this code in HeapTupleSatisfiesVacuumHorizon:
> > 
> >         else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
> >         {
> >             [...]
> >             /* inserted and then deleted by same xact */
> >             if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetUpdateXid(tuple)))
> >                 return HEAPTUPLE_DELETE_IN_PROGRESS;
> > 
> > Why HEAPTUPLE_DELETE_IN_PROGRESS and not HEAPTUPLE_DEAD?
>
> Please correct me if I'm wrong, despite tuples being inserted and deleted by the same 
> transaction - they are visible inside the transaction and usable by it, so considering them
> dead and cleaning up during execution is a bad idea until the transaction is ended.

But once they are deleted or updated, even the transaction that created them cannot
see them any more, right?

Yours,
Laurenz Albe



Re: Tuples inserted and deleted by the same transaction

From
Pantelis Theodosiou
Date:
On Tue, Sep 13, 2022 at 11:04 AM Laurenz Albe <laurenz.albe@cybertec.at> wrote:
>
> On Tue, 2022-09-13 at 11:47 +0300, Nikita Malakhov wrote:
> > On Tue, Sep 13, 2022 at 11:06 AM Laurenz Albe <laurenz.albe@cybertec.at> wrote:
> > > Shouldn't such tuples be considered dead right away, even if the inserting
> > > transaction is still active?  That would allow cleaning them up even before
> > > the transaction is done.
> > >
> > > There is this code in HeapTupleSatisfiesVacuumHorizon:
> > >
> > >         else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
> > >         {
> > >             [...]
> > >             /* inserted and then deleted by same xact */
> > >             if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetUpdateXid(tuple)))
> > >                 return HEAPTUPLE_DELETE_IN_PROGRESS;
> > >
> > > Why HEAPTUPLE_DELETE_IN_PROGRESS and not HEAPTUPLE_DEAD?
> >
> > Please correct me if I'm wrong, despite tuples being inserted and deleted by the same
> > transaction - they are visible inside the transaction and usable by it, so considering them
> > dead and cleaning up during execution is a bad idea until the transaction is ended.
>
> But once they are deleted or updated, even the transaction that created them cannot
> see them any more, right?

Forgive me if this is not related but if there is a savepoint between
the insertion and deletion, wouldn't it be possible for the
transaction to recover the deleted tuples?

Best regards
Pantelis Theodosiou



Re: Tuples inserted and deleted by the same transaction

From
Matthias van de Meent
Date:
On Tue, 13 Sep 2022, 12:04 Laurenz Albe, <laurenz.albe@cybertec.at> wrote:
>
> On Tue, 2022-09-13 at 11:47 +0300, Nikita Malakhov wrote:
>> Please correct me if I'm wrong, despite tuples being inserted and deleted by the same
>> transaction - they are visible inside the transaction and usable by it, so considering them
>> dead and cleaning up during execution is a bad idea until the transaction is ended.
>
> But once they are deleted or updated, even the transaction that created them cannot
> see them any more, right?


Not quite. The command that is deleting the tuple might still be
running, and because deletions are only "visible" to statements at the
end of the delete operation, that command may still need to see the
deleted tuple (example: DELETE FROM tab t WHERE t.randnum > (select
count(*) from tab)); that count(*) will not change during the delete
operation.

So in order to mark that tuple as all_dead, you need proof that the
deleting statement finished executing. I can think of two ways to do
that: either the commit/abort of that transaction (this would be
similarly expensive as the normal commit lookup), or (e.g.) the
existence of another tuple with the same XID but with a newer CID.
That last one would not be impossible, but probably not worth the
extra cost of command id tracking.

Kind regards,

Matthias van de Meent



Re: Tuples inserted and deleted by the same transaction

From
Matthias van de Meent
Date:
On Tue, 13 Sept 2022 at 12:40, Pantelis Theodosiou <ypercube@gmail.com> wrote:
>
> Forgive me if this is not related but if there is a savepoint between
> the insertion and deletion, wouldn't it be possible for the
> transaction to recover the deleted tuples?

Savepoints result in changed TransactionIds (well, subtransactions
with their own ids), so if a tuple was created before a savepoint and
deleted after, the values in xmin and xmax would be different, as you
can see in the following:

matthias=> CREATE TABLE tst(i int);
matthias=> BEGIN; INSERT INTO tst VALUES (1); SAVEPOINT s1; DELETE
FROM tst; ROLLBACK TO SAVEPOINT s1;
CREATE TABLE
BEGIN
INSERT 0 1
SAVEPOINT
DELETE 1
ROLLBACK
matthias=*> SELECT xmin, xmax FROM tst;
 xmin  | xmax
-------+-------
 62468 | 62469
(1 row)

Note that this row has different xmin/xmax from being created and
deleted in different subtransactions. This means that this needs no
specific handling in the HTSVH code that Laurenz asked about.


Kind regards,

Matthias van de Meent



Re: Tuples inserted and deleted by the same transaction

From
Tom Lane
Date:
Laurenz Albe <laurenz.albe@cybertec.at> writes:
> But once they are deleted or updated, even the transaction that created them cannot
> see them any more, right?

I would not trust that claim very far.  The transaction might have active
snapshots with a command ID between the times of insertion and deletion.
(Consider a query that is firing triggers as it goes, and the triggers
are performing new actions that cause the command counter to advance.
The outer query should not see the results of those actions.)

            regards, tom lane



Re: Tuples inserted and deleted by the same transaction

From
Matthias van de Meent
Date:
On Tue, 13 Sept 2022 at 15:45, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>
> Laurenz Albe <laurenz.albe@cybertec.at> writes:
> > But once they are deleted or updated, even the transaction that created them cannot
> > see them any more, right?
>
> I would not trust that claim very far.  The transaction might have active
> snapshots with a command ID between the times of insertion and deletion.
> (Consider a query that is firing triggers as it goes, and the triggers
> are performing new actions that cause the command counter to advance.
> The outer query should not see the results of those actions.)

I hadn't realized that triggers indeed consume command ids but might
not be visible to the outer query (that might still be running). That
invalidates the "or (e.g.) the existence of another tuple with the
same XID but with a newer CID" claim I made earlier, so thanks for
clarifying.

Kind regards,

Matthias van de Meent



Re: Tuples inserted and deleted by the same transaction

From
Laurenz Albe
Date:
On Tue, 2022-09-13 at 16:13 +0200, Matthias van de Meent wrote:
> On Tue, 13 Sept 2022 at 15:45, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> > Laurenz Albe <laurenz.albe@cybertec.at> writes:
> > > But once they are deleted or updated, even the transaction that created them cannot
> > > see them any more, right?
> > 
> > I would not trust that claim very far.  The transaction might have active
> > snapshots with a command ID between the times of insertion and deletion.
> > (Consider a query that is firing triggers as it goes, and the triggers
> > are performing new actions that cause the command counter to advance.
> > The outer query should not see the results of those actions.)
> 
> I hadn't realized that triggers indeed consume command ids but might
> not be visible to the outer query (that might still be running). That
> invalidates the "or (e.g.) the existence of another tuple with the
> same XID but with a newer CID" claim I made earlier, so thanks for
> clarifying.

Yes, that makes sense.  Thanks.

Yours,
Laurenz Albe