Re: Add 64-bit XIDs into PostgreSQL 15 - Mailing list pgsql-hackers

From Daniil Davydov
Subject Re: Add 64-bit XIDs into PostgreSQL 15
Date
Msg-id CAJDiXghosLZQzBfsTf7QCoo-eTGAyYOBa90A46Et=udbL0_QPA@mail.gmail.com
Whole thread Raw
In response to Re: Add 64-bit XIDs into PostgreSQL 15  ("Maksim.Melnikov" <m.melnikov@postgrespro.ru>)
Responses Re: Add 64-bit XIDs into PostgreSQL 15
List pgsql-hackers
Hi,

On Thu, Jul 17, 2025 at 8:36 PM Maksim.Melnikov
<m.melnikov@postgrespro.ru> wrote:
>
> On 07.07.2025 11:17, Evgeny Voropaev wrote:
> > Do-side:
> > 1. Having page ABC with several tuples.
> > 2. Starting to perform insertion of new tuple
> >    2.1. In the case of an inappropriate xid_base, trying to fit base
> >    2.1.1 Freezing and pruning tuples without further repairing
> > fragmentation.
> >     2.1.2 All tuples have been pruned (no alive tuples on the page
> > since this moment)
> > 3. Inserting a new tuple and setting XLOG_HEAP_INIT_PAGE, assuming
> > that the only tuple located at the bottom of the page (assuming that
> > fragmentation has been performed).
> >
> >
> > Result: We have the ABC page with the new tuple inserted somewhere in
> > the MIDDLE of the page and surrounded with garbage from dead and
> > unused tuples. At the same time we have an xlog record bringing the
> > XLOG_HEAP_INIT_PAGE bit.
> >
> > Redo-side
> > 1. Observing XLOG_HEAP_INIT_PAGE
> > 2. Creating a new page and inserting the new tuple into the first
> > position of the page.
>
>
> Evgeny, I've tried to reproduce described scenario, but I can't get
> XLOG_HEAP_INIT_PAGE bit set.
>
> In attached file you can find detailed test description with results, so
> you can repeat it.
>
> Maybe I missed something in your scenario, can you please clarify?
> Or maybe it is't reproducable at all.
>

I have also tried to reproduce this bug. To do this, we need several
conditions:
1) New tuple must be "linked" with the first line pointer on page
2) At the time the new tuple is inserted, there should be another
    tuple (A) on the page.
3) Freeze&prune must be able to truncate line pointer of the
    tuple (A)

We can easily reach (1), (2) conditions :
1. Insert two tuples;
2. Delete first of them;
4. Call vacuum on table
5. Delete second tuple
6. Advance xid into the future (for example, via pg_resetwal)
6. Insert new tuple

Thus, the new tuple will be associated with the first line pointer,
and the page will have one dead tuple (associated with the second
line pointer).

But as far as I understand, (3) condition is unreachable, because we
just cannot truncate the line pointer of the second tuple (and prune
tuple itself).

Possibly, it could have happened inside freeze_single_heap_page, but
this function cannot mark the line pointer of the second tuple as LP_UNUSED
(we don't specify HEAP_PAGE_PRUNE_MARK_UNUSED_NOW flag for
heap_page_prune_and_freeze call).

As a result, the page will always have more than one line pointer.
Interference of parallel operations is excluded because we have an
exclusive lock on buffer during heap_page_prepare_for_xid call.

Maybe we have operations that might mark line pointers as unused
without repairing fragmentation (it might be useful for reproduction of
this bug), but I didn't find any.

BTW, I think that "phdr->pd_special == phdr->pd_upper" is the best way
to decide whether we need to set the XLOG_HEAP_INIT_PAGE
flag to WAL record (at least this would eliminate the occurrence of the
described problem).

--
Best regards,
Daniil Davydov



pgsql-hackers by date:

Previous
From: Amit Kapila
Date:
Subject: Re: Logical Replication of sequences
Next
From: Dilip Kumar
Date:
Subject: Re: Logical Replication of sequences