From: Robert Haas Date: Thu, 28 Oct 2021 16:18:40 +0000 (-0400) Subject: Change read_local_xlog_page so that it does not change ThisTimeLineID. X-Git-Url: http://git.postgresql.org/gitweb/?a=commitdiff_plain;h=c1638d402a2ddf7b72e8bb0102f129250a57ebc2;p=users%2Frhaas%2Fpostgres.git Change read_local_xlog_page so that it does not change ThisTimeLineID. 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. --- diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c index f6e7fa71d8..ef4b5f639c 100644 --- a/src/backend/access/transam/twophase.c +++ b/src/backend/access/transam/twophase.c @@ -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(), diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c index c40500a6f2..9ad2ce533e 100644 --- a/src/backend/access/transam/xlogutils.c +++ b/src/backend/access/transam/xlogutils.c @@ -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) diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c index d09bffaa9d..10603b2d86 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -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; diff --git a/src/include/access/xlogutils.h b/src/include/access/xlogutils.h index a5cb3d322c..eebc91f3a5 100644 --- a/src/include/access/xlogutils.h +++ b/src/include/access/xlogutils.h @@ -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);