Change read_local_xlog_page so that it does not change ThisTimeLineID.
authorRobert Haas <[email protected]>
Thu, 28 Oct 2021 16:18:40 +0000 (12:18 -0400)
committerRobert Haas <[email protected]>
Fri, 29 Oct 2021 17:38:50 +0000 (13:38 -0400)
To make that work, change XLogReadDetermineTimeline to take a TLI
as an argument instead of having it depend on the global variable.

With that done, XlogReadTwoPhaseData doesn't need to save and
restore the value, so remove that logic.

src/backend/access/transam/twophase.c
src/backend/access/transam/xlogutils.c
src/backend/replication/walsender.c
src/include/access/xlogutils.h

index f6e7fa71d8887554febe5afe7f419e39a027838b..ef4b5f639ced42ee44b16b6db94f3a1593284aa4 100644 (file)
@@ -1373,11 +1373,7 @@ ReadTwoPhaseFile(TransactionId xid, bool missing_ok)
  * twophase files and ReadTwoPhaseFile should be used instead.
  *
  * Note clearly that this function can access WAL during normal operation,
- * similarly to the way WALSender or Logical Decoding would do.  While
- * accessing WAL, read_local_xlog_page() may change ThisTimeLineID,
- * particularly if this routine is called for the end-of-recovery checkpoint
- * in the checkpointer itself, so save the current timeline number value
- * and restore it once done.
+ * similarly to the way WALSender or Logical Decoding would do.
  */
 static void
 XlogReadTwoPhaseData(XLogRecPtr lsn, char **buf, int *len)
@@ -1385,7 +1381,6 @@ XlogReadTwoPhaseData(XLogRecPtr lsn, char **buf, int *len)
        XLogRecord *record;
        XLogReaderState *xlogreader;
        char       *errormsg;
-       TimeLineID      save_currtli = ThisTimeLineID;
 
        xlogreader = XLogReaderAllocate(wal_segment_size, NULL,
                                                                        XL_ROUTINE(.page_read = &read_local_xlog_page,
@@ -1401,13 +1396,6 @@ XlogReadTwoPhaseData(XLogRecPtr lsn, char **buf, int *len)
        XLogBeginRead(xlogreader, lsn);
        record = XLogReadRecord(xlogreader, &errormsg);
 
-       /*
-        * Restore immediately the timeline where it was previously, as
-        * read_local_xlog_page() could have changed it if the record was read
-        * while recovery was finishing or if the timeline has jumped in-between.
-        */
-       ThisTimeLineID = save_currtli;
-
        if (record == NULL)
                ereport(ERROR,
                                (errcode_for_file_access(),
index c40500a6f2bad0f0b96fbc98a128169dfd829a5c..9ad2ce533e783d5a0a1fe50785966d50bbf720f6 100644 (file)
@@ -678,6 +678,10 @@ XLogTruncateRelation(RelFileNode rnode, ForkNumber forkNum,
  * wantLength to the amount of the page that will be read, up to
  * XLOG_BLCKSZ. If the amount to be read isn't known, pass XLOG_BLCKSZ.
  *
+ * The currTLI argument should be the system-wide current timeline.
+ * Note that this may be different from state->currTLI, which is the timeline
+ * from which the caller is currently reading previous xlog records.
+ *
  * We switch to an xlog segment from the new timeline eagerly when on a
  * historical timeline, as soon as we reach the start of the xlog segment
  * containing the timeline switch.  The server copied the segment to the new
@@ -699,12 +703,11 @@ XLogTruncateRelation(RelFileNode rnode, ForkNumber forkNum,
  *
  * The caller must also make sure it doesn't read past the current replay
  * position (using GetXLogReplayRecPtr) if executing in recovery, so it
- * doesn't fail to notice that the current timeline became historical. The
- * caller must also update ThisTimeLineID with the result of
- * GetXLogReplayRecPtr and must check RecoveryInProgress().
+ * doesn't fail to notice that the current timeline became historical.
  */
 void
-XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage, uint32 wantLength)
+XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage,
+                                                 uint32 wantLength, TimeLineID currTLI)
 {
        const XLogRecPtr lastReadPage = (state->seg.ws_segno *
                                                                         state->segcxt.ws_segsize + state->segoff);
@@ -732,12 +735,12 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage, uint32 wa
         * just carry on. (Seeking backwards requires a check to make sure the
         * older page isn't on a prior timeline).
         *
-        * ThisTimeLineID might've become historical since we last looked, but the
-        * caller is required not to read past the flush limit it saw at the time
-        * it looked up the timeline. There's nothing we can do about it if
-        * StartupXLOG() renames it to .partial concurrently.
+        * currTLI might've become historical since the caller obtained the value,
+        * but the caller is required not to read past the flush limit it saw at
+        * the time it looked up the timeline. There's nothing we can do about it
+        * if StartupXLOG() renames it to .partial concurrently.
         */
-       if (state->currTLI == ThisTimeLineID && wantPage >= lastReadPage)
+       if (state->currTLI == currTLI && wantPage >= lastReadPage)
        {
                Assert(state->currTLIValidUntil == InvalidXLogRecPtr);
                return;
@@ -749,7 +752,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage, uint32 wa
         * the current segment we can just keep reading.
         */
        if (state->currTLIValidUntil != InvalidXLogRecPtr &&
-               state->currTLI != ThisTimeLineID &&
+               state->currTLI != currTLI &&
                state->currTLI != 0 &&
                ((wantPage + wantLength) / state->segcxt.ws_segsize) <
                (state->currTLIValidUntil / state->segcxt.ws_segsize))
@@ -772,7 +775,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage, uint32 wa
                 * We need to re-read the timeline history in case it's been changed
                 * by a promotion or replay from a cascaded replica.
                 */
-               List       *timelineHistory = readTimeLineHistory(ThisTimeLineID);
+               List       *timelineHistory = readTimeLineHistory(currTLI);
                XLogRecPtr      endOfSegment;
 
                endOfSegment = ((wantPage / state->segcxt.ws_segsize) + 1) *
@@ -853,6 +856,7 @@ read_local_xlog_page(XLogReaderState *state, XLogRecPtr targetPagePtr,
        TimeLineID      tli;
        int                     count;
        WALReadError errinfo;
+       TimeLineID      currTLI;
 
        loc = targetPagePtr + reqLen;
 
@@ -864,10 +868,10 @@ read_local_xlog_page(XLogReaderState *state, XLogRecPtr targetPagePtr,
                 * most recent timeline is.
                 */
                if (!RecoveryInProgress())
-                       read_upto = GetFlushRecPtr(&ThisTimeLineID);
+                       read_upto = GetFlushRecPtr(&currTLI);
                else
-                       read_upto = GetXLogReplayRecPtr(&ThisTimeLineID);
-               tli = ThisTimeLineID;
+                       read_upto = GetXLogReplayRecPtr(&currTLI);
+               tli = currTLI;
 
                /*
                 * Check which timeline to get the record from.
@@ -886,16 +890,16 @@ read_local_xlog_page(XLogReaderState *state, XLogRecPtr targetPagePtr,
                 * archive in the timeline will get renamed to .partial by
                 * StartupXLOG().
                 *
-                * If that happens after our caller updated ThisTimeLineID but before
+                * If that happens after our caller determined the TLI but before
                 * we actually read the xlog page, we might still try to read from the
                 * old (now renamed) segment and fail. There's not much we can do
                 * about this, but it can only happen when we're a leaf of a cascading
                 * standby whose primary gets promoted while we're decoding, so a
                 * one-off ERROR isn't too bad.
                 */
-               XLogReadDetermineTimeline(state, targetPagePtr, reqLen);
+               XLogReadDetermineTimeline(state, targetPagePtr, reqLen, tli);
 
-               if (state->currTLI == ThisTimeLineID)
+               if (state->currTLI == currTLI)
                {
 
                        if (loc <= read_upto)
index d09bffaa9dc03ca401296e20922589be6f78d262..10603b2d86272ebbabf3d32158733b17a5671aa5 100644 (file)
@@ -910,7 +910,7 @@ logical_read_xlog_page(XLogReaderState *state, XLogRecPtr targetPagePtr, int req
        WALReadError errinfo;
        XLogSegNo       segno;
 
-       XLogReadDetermineTimeline(state, targetPagePtr, reqLen);
+       XLogReadDetermineTimeline(state, targetPagePtr, reqLen, ThisTimeLineID);
        sendTimeLineIsHistoric = (state->currTLI != ThisTimeLineID);
        sendTimeLine = state->currTLI;
        sendTimeLineValidUpto = state->currTLIValidUntil;
index a5cb3d322c52f9c6827a7a98c670e01dbdc48d09..eebc91f3a5061edb1fb93f9d220767b97fa8cb07 100644 (file)
@@ -98,7 +98,9 @@ extern void wal_segment_open(XLogReaderState *state,
 extern void wal_segment_close(XLogReaderState *state);
 
 extern void XLogReadDetermineTimeline(XLogReaderState *state,
-                                                                         XLogRecPtr wantPage, uint32 wantLength);
+                                                                         XLogRecPtr wantPage,
+                                                                         uint32 wantLength,
+                                                                         TimeLineID currTLI);
 
 extern void WALReadRaiseError(WALReadError *errinfo);