Re: Race condition in recovery?
Kyotaro Horiguchi <horikyota.ntt@gmail.com>
From: Kyotaro Horiguchi <horikyota.ntt@gmail.com>
To: dilipbalaut@gmail.com
Cc: robertmhaas@gmail.com, hlinnaka@iki.fi,
pgsql-hackers@lists.postgresql.org
Date: 2021-05-18T06:52:07Z
Lists: pgsql-hackers
Attachments
- (unnamed) (text/plain)
At Mon, 17 May 2021 10:46:24 +0530, Dilip Kumar <dilipbalaut@gmail.com> wrote in
> On Mon, May 17, 2021 at 10:09 AM Dilip Kumar <dilipbalaut@gmail.com> wrote:
> >
> > On Mon, May 17, 2021 at 8:50 AM Kyotaro Horiguchi
> > <horikyota.ntt@gmail.com> wrote:
> > >
> > > Before the commit expectedTLEs is always initialized with just one
> > > entry for the TLI of the last checkpoint record.
> >
> > Right
> >
> > > (1) If XLogFileReadAnyTLI() found the segment but no history file
> > > found, that is, using the dummy TLE-list, expectedTLEs is initialized
> > > with the dummy one-entry list. So there's no behavioral change in this
> > > aspect.
> >
> > Yeah, you are right.
>
> But do you agree that one line entry will always be a checkpoint
> timeline entry? Because if you notice below code[1] in function
> "readRecoveryCommandFile();", then you will realize that once we come
> out of this function either the "recoveryTargetTLI" is checkpoint TL
> wherever it was before calling this function or we must have the
> history file. That means after exiting this function if we execute
> this line (expectedTLEs = readTimeLineHistory(recoveryTargetTLI);)
> that means either "expectedTLEs" could point to one dummy entry which
> will be nothing but the checkpoint TL entry or it will be holding
> complete history.
Right.
> The patch is trying to say that without the history file the
> checkpoint TL will not be found in "expectedTLEs" because the older TL
> (checkpoint TL) is not the ancestor of the target
> timeline(recoveryTargetTLI). But ideally, either the target timeline
> should be the same as the checkpoint timeline or we must have the
> history file as I stated in the above paragraph. Am I missing
> something?
Yeah, that has been the most mysterious point here. So I searched for
a situation the one-entry expectedTLEs does not work.
I vaguely believed that there's a case where REDO point of a
checkpoint is in the timeline previous to the record of the
checkpoint. The previous discussion is based on this case, but that
doesn't seem to happen. The last replayed checkpoint (that causes a
restartpoint) record is found before protmotion and the first
checkpoint starts after promotion.
A little while ago I tried to make a situation where a checkpoint
record is placed in the previous timeline of the tli written in the
control file. But control file is always written after checkpoint
record is flushed.
I rebooted myself from this:
ee994272ca:
> There is at least one scenario where this makes a difference: if you take
> a base backup from a standby server right after a timeline switch, the
> WAL segment containing the initial checkpoint record will begin with an
> older timeline ID. Without the timeline history file, recovering that file
And finally I think I could reach the situation the commit wanted to fix.
I took a basebackup from a standby just before replaying the first
checkpoint of the new timeline (by using debugger), without copying
pg_wal. In this backup, the control file contains checkPointCopy of
the previous timeline.
I modified StartXLOG so that expectedTLEs is set just after first
determining recoveryTargetTLI, then started the grandchild node. I
have the following error and the server fails to continue replication.
[postmaster] LOG: starting PostgreSQL 14beta1 on x86_64-pc-linux-gnu...
[startup] LOG: database system was interrupted while in recovery at log...
[startup] LOG: set expectedtles tli=6, length=1
[startup] LOG: Probing history file for TLI=7
[startup] LOG: entering standby mode
[startup] LOG: scanning segment 3 TLI 6, source 0
[startup] LOG: Trying fetching history file for TLI=6
[walreceiver] LOG: fetching timeline history file for timeline 5 from pri...
[walreceiver] LOG: fetching timeline history file for timeline 6 from pri...
[walreceiver] LOG: started streaming ... primary at 0/3000000 on timeline 5
[walreceiver] DETAIL: End of WAL reached on timeline 5 at 0/30006E0.
[startup] LOG: unexpected timeline ID 1 in log segment 000000050000000000000003, offset 0
[startup] LOG: Probing history file for TLI=7
[startup] LOG: scanning segment 3 TLI 6, source 0
(repeats forever)
This seems like the behavior the patch wanted to fix. (I'm not sure
precisely what happened at the time of the "unexpected timeline ID
1..", though. The line is seen only just after the first conection.)
> will fail as the older timeline ID is not recognized to be an ancestor of
> the target timeline. If you try to recover from such a backup, using only
> streaming replication to fetch the WAL, this patch is required for that to
> work.
After I reverted the modification, I got the following behavior
instead from the same backup.
[postmaster] LOG: starting PostgreSQL 14beta1 on x86_64-...
[startup] JST LOG: database system was interrupted while in recovery at log time 2021-05-18 13:45:59 JST
[startup] JST LOG: Probing history file for TLI=7
[startup] JST LOG: entering standby mode
[startup] JST LOG: Loading history file for TLI=6 (2)
[startup] JST LOG: Trying reading history file for TLI=6
[startup] JST LOG: scanning segment 3 TLI 6, source 0
[startup] JST LOG: Trying fetching history file for TLI=6
[walreceiver] JST LOG: fetching timeline history file for timeline 5 fro...
[walreceiver] JST LOG: fetching timeline history file for timeline 6 fro...
[walreceiver] JST LOG: started streaming ... primary at 0/3000000 on timeline 5
[walreceiver] JST LOG: replication terminated by primary server
[walreceiver] JST DETAIL: End of WAL reached on timeline 5 at 0/30006E0.
[startup] LOG: Loading expectedTLEs for 5
[startup] LOG: Trying reading history file for TLI=5
[startup] LOG: Checkpoint record: TLI=5, 0/3000668, rectargetTLI=6, exptles=0x3322a60
[startup] FATAL: requested timeline 6 does not contain minimum recovery point 0/30007C0 on timeline 6
[postmaster] LOG: startup process (PID 76526) exited with exit code 1
[postmaster] LOG: aborting startup due to startup process failure
[postmaster] LOG: database system is shut down
Aborts.. Yeah, this is the same issue with what is railed here. So,
still I'm not sure I confirmed the case exactly (since the problem is
still seen.. but I don't want to bother building the version.)...
Anyway reading history file for recoveryTargetTLI instead of
receiveTLI fixes that.
FWIW, you could be get a problematic base backup by the following steps.
0. (make sure /tmp/hoge is removed)
1. apply the attached patch
2. create a primary then start
3. create a standby then start
4. place standby.signal to the primary, then restart it.
5. place the file /tmp/hoge.
6. promote the "primary".
7. You will see a log line like this
LOG: WAIT START: CHECKPOINT_ONLINE: TLI=2
8. Take a base backup (without copying WAL files)
> [1]
> if (rtli)
> {
> /* Timeline 1 does not have a history file, all else should */
> if (rtli != 1 && !existsTimeLineHistory(rtli))
> ereport(FATAL,
> (errmsg("recovery target timeline %u does not exist",
> rtli)));
> recoveryTargetTLI = rtli;
> recoveryTargetIsLatest = false;
> }
> else
> {
> /* We start the "latest" search from pg_control's timeline */
> recoveryTargetTLI = findNewestTimeLine(recoveryTargetTLI);
> recoveryTargetIsLatest = true;
> }
regards.
--
Kyotaro Horiguchi
NTT Open Source Software Center
Commits
-
Further refinement of stuck_on_old_timeline recovery test
- e46f6a078c1a 9.6.23 landed
- 1dc53c914fe8 10.18 landed
- c0a7587807dd 11.13 landed
- fb3d6b0e1aa4 12.8 landed
- d906d106f854 13.4 landed
- 54a5ed220169 14.0 landed
-
Adjust new test case to set wal_keep_segments.
- 6cd0e55f9ffb 9.6.23 landed
- 1c2c6a9a299c 10.18 landed
- 534b9be805b4 11.13 landed
- 2208d71a0099 12.8 landed
-
Adjust new test case to set wal_keep_size.
- 3465328aa19e 13.4 landed
- 4dcb1d087aeb 14.0 landed
-
Fix corner case failure of new standby to follow new primary.
- 6eb5b9ae3917 9.6.23 landed
- 31bda6a22ad1 10.18 landed
- ca158c168ea3 11.13 landed
- 5d950c721d38 12.8 landed
- 082656429215 13.4 landed
- caba8f0d43fb 14.0 landed
-
Back-port a few PostgresNode.pm methods.
- 75212a854f99 9.6.23 landed
-
Allow PostgresNode.pm's backup method to accept backup_options.
- 9778a191a4c0 10.18 landed
- 38982b8b7bd9 11.13 landed
- 6fc2febc28ae 12.8 landed
- 99a0a2ada8c5 13.4 landed
-
Add end-to-end testing of pg_basebackup's tar-format output.
- 081876d75ea1 14.0 cited
-
Allow PostgresNode.pm tests to wait for catchup
- fb093e4cb36f 10.0 cited
-
Delay reading timeline history file until it's fetched from master.
- ee994272ca50 9.3.0 cited