| From: | Andrey Rachitskiy <pl0h0yp1(at)gmail(dot)com> |
|---|---|
| To: | Филиппов Степан <stepan(dot)filippov(at)yandex(dot)ru> |
| Cc: | "pgsql-hackers(at)lists(dot)postgresql(dot)org" <pgsql-hackers(at)lists(dot)postgresql(dot)org>, "heikki(dot)linnakangas(at)iki(dot)fi" <heikki(dot)linnakangas(at)iki(dot)fi>, michael(at)paquier(dot)xyz |
| Subject: | Re: [PATCH] Fix timeline history after recovery stops on an ancestor |
| Date: | 2026-08-01 17:28:55 |
| Message-ID: | CAB8bMiumwhY6+6JNPYwkZrw0Hn+nq1zRKJcUj-aV+XGk=z4=Xg@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
Hi Stepan,
I looked at this and I think the diagnosis is right.
When archive recovery stops on an ancestor before the switch into
recoveryTargetTLI, the end-of-recovery path already treats
endOfRecoveryInfo->lastRecTLI as the timeline we are leaving
(PrevTimeLineID / the end-of-recovery record). writeTimeLineHistory()
was the odd one out: it still recorded recoveryTargetTLI as the parent,
so the new .history file copied a later switch and then appended an
earlier switchpoint. That is not a usable ancestry for anything that
walks timeline history.
Using lastRecTLI as the parent matches what recovery actually did.
endOfLogTLI would be the wrong substitute here: in the 028 scenario the
last records are still on timeline 1, even though they were read from a
segment whose filename carries timeline 2. Leaving
findNewestTimeLine(recoveryTargetTLI) + 1 alone also looks correct; the
new TLI must be unused in the archive, while the parent is a separate
question.
Heikki, Michael — you've spent a lot of time in this area (028 itself,
the "follow last replayed TLI" idea in walsenders, and the surrounding
recovery/timeline maintenance). If you have a moment, it would be
good to hear whether using lastRecTLI as the history parent is the
right long-term shape, or whether I'm missing a case where
recoveryTargetTLI is still required.
This also seems adjacent to the recent archive-recovery / timeline
threads [1][2]: once .history lies about ancestry, consumers that
trust it are on thin ice.
[1]
https://www.postgresql.org/message-id/flat/85386EF6-16B7-4D62-86BE-526A10F93825%40yandex-team.ru
[2]
https://www.postgresql.org/message-id/flat/CA%2BTgmobr27GpKDZx3_ezW2%2BC5_g18i%2BjSK3sGF_cR-_ESv5N5A%40mail.gmail.com
пт, 31 июл. 2026 г. в 13:36, Филиппов Степан <stepan(dot)filippov(at)yandex(dot)ru>:
>
> Hi hackers,
>
> While working on WAL verification, we found a case where a timeline
> history file does not describe the sequence of timeline switches that
> actually took place.
>
> Suppose timeline 2 forked from timeline 1 at LSN B. We then perform
> PITR with recovery_target_timeline = 'latest', but stop at a restore
> point A on timeline 1, where A < B. PostgreSQL allocates timeline 3,
> but currently records recoveryTargetTLI, i.e. timeline 2, as its
> parent. The resulting history looks like this:
>
> cat 000002.history:
> 1 B ...
> 2 A ...
>
> The switchpoints run backwards. The actual ancestry is a direct fork
> from timeline 1 to timeline 3 at A. A consumer such as a WAL verifier
> cannot reconstruct that ancestry from the history file.
>
> The attached patch uses the timeline of the last replayed WAL record
> as the parent of the new timeline. It also adjusts 028_pitr_timelines.pl
> to check the generated history file.
>
> This came up while looking at the following related discussions [0] & [1]
>
> I think this is a correctness issue and should be backpatched.
>
>
> [0]
> https://www.postgresql.org/message-id/flat/CA%2BTgmobr27GpKDZx3_ezW2%2BC5_g18i%2BjSK3sGF_cR-_ESv5N5A%40mail.gmail.com
>
> [1]
> https://www.postgresql.org/message-id/flat/85386EF6-16B7-4D62-86BE-526A10F93825%40yandex-team.ru
>
>
> Regards,
> Stepan Filippov,
> Yandex Cloud.
>
>
--
Regards,
Rachitskiy Andrey
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Alexander Lakhin | 2026-08-01 18:00:00 | Re: Improving tracking/processing of buildfarm test failures |
| Previous Message | Kevin Rocker | 2026-08-01 16:57:28 | [PATCH] Fix vacuum_delay_point happening inside lock |