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, pgsql-hackers@lists.postgresql.org
Date: 2021-05-07T02:53:02Z
Lists: pgsql-hackers
Attachments
At Tue, 4 May 2021 17:41:06 +0530, Dilip Kumar <dilipbalaut@gmail.com> wrote in > I think the fix for the problem will be that, after reading/validating > the checkpoint record, we can free the current value of expectedTLEs > and reinitialize it based on the recoveryTargetTLI as shown in the > attached patch? I'm not sure I understand the issue here. I think that the attached should reproduce the issue mentioned here, but didn't for me. The result of running the attached test script is shown below. TLIs are adjusted in your descriptions cited below. The lines prefixed by NodeN> are the server log lines written while running the attached test script. > 1. Node2 got promoted to new primary, and node 2 picked new TL 2 in > the middle of the segment 3. Node2> LOG: selected new timeline ID: 2 > 2. Node3, restarted with new primary info of Node2 and restore command Node2> node_3 LOG: received replication command: IDENTIFY_SYSTEM > 3. Node3, found the newest TL2 in validateRecoveryParameters() Because > the latest TL was requested in recovery.conf (history file restored > from TL2) and set recoveryTargetTLI to 2 So point to note is > recoveryTargetTLI is set to 2 but expectedTLEs is not yet set. This means you specified recovery_target_timeline? Either way, expectedTLEs is not relevant to the behavior here. Even if recovery_target_timeline is set to latest, findNewestTimeLine doesn't look it. Node3> LOG: restored log file "00000002.history" from archive > 4. Node3, entered into the standby mode. Node3> LOG: entering standby mode > 5. Node3, tries to read the checkpoint Record, on Node3 still the > checkpoint TL (ControlFile->checkPointCopy.ThisTimeLineID) is 1. expectedTLEs is loaded just before fetching the last checkpoint. ReadCheckpointRecord doesn't consider checkPointCopy.ThisTimeLineID. The reason for the checkpoint TLI is that the segment file was that of the newest TLI in expectedTLEs found in pg_wal directory. If the segment for TLI=2 containing the last checkpoint had been archived, checkpoint record would be read as TLI=2. Replication starts at TLI=2 in this case because archive recovery has reached that timeline. (Turn on the optional section in the attached test script to see this behavior.) This is the expected behavior since we assume that the segment files for TLI=n and n+1 are identical in the TLI=n part. Anyway the checkpoint that is read is on TLI=1 in this case and replication starts at TLI=1. Node3> LOG: Checkpoint record: TLI=1, 0/3014F78 > 6. Node3, tries to get the checkpoint record file using new TL2 from > the archive which it should get ideally but it may not if the Node2 > haven't yet archived it. This doesn't happen for me. Instead, node3 runs recovery from the checkpoint up to the end of the archived WAL. In this case the end point is 3014FF0@TLI=1. Node3> LOG: invalid record length at 0/3014FF0: wanted 24, got 0 Then, node3 connects to node2 requesting TLI=1 because the history file (or expectedTLEs) told that the LSN belongs to TLI=1. Node3> LOG: 0/3014FF0 is on TLI 1 Node3> LOG: started streaming WAL from primary at 0/3000000 on timeline 1 After a while node2 finds a timeline switch and disconnects the replication. Node3> LOG: replication terminated by primary server Node3> DETAIL: End of WAL reached on timeline 1 at 0/3029A68. After scanning the archive and pg_wal ends in failure, node3 correctly requests node2 for TLI=2 because expectedTLEs told that the current LSN belongs to TLI=2. Node3> LOG: 0/3029A68 is on TLI 2 Node3> LOG: restarted WAL streaming at 0/3000000 on timeline 2 Finally the items below don't happen for me, because node3 needs not to go back to the last checkpoint any longer. Perhaps the script is failing to reproduce your issue correctly. > 7. Node3, tries to stream from primary but using TL1 because > ControlFile->checkPointCopy.ThisTimeLineID is 1. As mentioned above, the checkPointCopy.ThisTimeLineID on either the primary and secondary is irrelevant to the timline the primary sends. The primary streams the timeline requested by the secondary. > 8. Node3, get it because walsender of Node2 read it from TL2 and send > it and Node2 write in the new WAL file but with TL1. Walsender strems the requested TLI from walreceiver, then disconnects at the end of the TLI notifying node3 of the next TLI. Node3 re-establishes replication with the new TLI. Looking into pg_wal of node3, segment 3 for both TLI=1 and 2 are filled by the correct content. So,,, I don't understand what are you saying is the race condition.. An issue that may be slightly relevant to this case have been raised [1]. But it is about writing end-of-recovery checkpoint into the older timeline. Could you please fix the test script so that it causes your issue correctly? And/or elaborate a bit more? The attached first file is the debugging aid logging. The second is the test script, to be placed in src/test/recovery/t. 1: https://www.postgresql.org/message-id/CAE-ML%2B_EjH_fzfq1F3RJ1%3DXaaNG%3D-Jz-i3JqkNhXiLAsM3z-Ew%40mail.gmail.com 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