xlog.c: Use XLogCtl->ThisTimeLineID in various places.
authorRobert Haas <[email protected]>
Mon, 1 Nov 2021 15:42:55 +0000 (11:42 -0400)
committerRobert Haas <[email protected]>
Mon, 1 Nov 2021 16:45:31 +0000 (12:45 -0400)
Where appropriate, instead of using ThisTimeLineID, use the value
from shared memory instead, to reduce dependencies on the global
variable. This is only safe after recovery is complete, because
prior to that, the global variable and the shared state don't
match.

This allows removal of some ugly logic in CreatRestartPoint() to
temporarily set ThisTimeLineID for purposes of tricking
RemoveOldXlogFiles and PreallocXlogFiles into doing the right thing,
and then clearing it again afterwards.

src/backend/access/transam/xlog.c

index 95b64e6093475c2c95c428e374676888bd60f880..054241403c55b420e3f71e32ddcc9a8a341d9635 100644 (file)
@@ -1035,6 +1035,7 @@ XLogInsertRecord(XLogRecData *rdata,
        XLogRecPtr      StartPos;
        XLogRecPtr      EndPos;
        bool            prevDoPageWrites = doPageWrites;
+       TimeLineID      insertTLI;
 
        /* we assume that all of the record header is in the first chunk */
        Assert(rdata->len >= SizeOfXLogRecord);
@@ -1043,6 +1044,12 @@ XLogInsertRecord(XLogRecData *rdata,
        if (!XLogInsertAllowed())
                elog(ERROR, "cannot make new WAL entries during recovery");
 
+       /*
+        * Given that we're not in recovery, ThisTimeLineID is set and can't
+        * change, so we can read it without a lock.
+        */
+       insertTLI = XLogCtl->ThisTimeLineID;
+
        /*----------
         *
         * We have now done all the preparatory work we can without holding a
@@ -1146,7 +1153,7 @@ XLogInsertRecord(XLogRecData *rdata,
                 * inserted. Copy the record in the space reserved.
                 */
                CopyXLogRecordToWAL(rechdr->xl_tot_len, isLogSwitch, rdata,
-                                                       StartPos, EndPos, ThisTimeLineID);
+                                                       StartPos, EndPos, insertTLI);
 
                /*
                 * Unless record is flagged as not important, update LSN of last
@@ -2901,6 +2908,7 @@ XLogFlush(XLogRecPtr record)
 {
        XLogRecPtr      WriteRqstPtr;
        XLogwrtRqst WriteRqst;
+       TimeLineID      insertTLI = XLogCtl->ThisTimeLineID;
 
        /*
         * During REDO, we are reading not writing WAL.  Therefore, instead of
@@ -3021,7 +3029,7 @@ XLogFlush(XLogRecPtr record)
                WriteRqst.Write = insertpos;
                WriteRqst.Flush = insertpos;
 
-               XLogWrite(WriteRqst, ThisTimeLineID, false);
+               XLogWrite(WriteRqst, insertTLI, false);
 
                LWLockRelease(WALWriteLock);
                /* done */
@@ -3093,11 +3101,18 @@ XLogBackgroundFlush(void)
        static TimestampTz lastflush;
        TimestampTz now;
        int                     flushbytes;
+       TimeLineID      insertTLI;
 
        /* XLOG doesn't need flushing during recovery */
        if (RecoveryInProgress())
                return false;
 
+       /*
+        * Since we're not in recovery, ThisTimeLineID is set and can't change,
+        * so we can read it without a lock.
+        */
+       insertTLI = XLogCtl->ThisTimeLineID;
+
        /* read LogwrtResult and update local state */
        SpinLockAcquire(&XLogCtl->info_lck);
        LogwrtResult = XLogCtl->LogwrtResult;
@@ -3188,7 +3203,7 @@ XLogBackgroundFlush(void)
        if (WriteRqst.Write > LogwrtResult.Write ||
                WriteRqst.Flush > LogwrtResult.Flush)
        {
-               XLogWrite(WriteRqst, ThisTimeLineID, flexible);
+               XLogWrite(WriteRqst, insertTLI, flexible);
        }
        LWLockRelease(WALWriteLock);
 
@@ -3201,7 +3216,7 @@ XLogBackgroundFlush(void)
         * Great, done. To take some work off the critical path, try to initialize
         * as many of the no-longer-needed WAL buffers for future use as we can.
         */
-       AdvanceXLInsertBuffer(InvalidXLogRecPtr, ThisTimeLineID, true);
+       AdvanceXLInsertBuffer(InvalidXLogRecPtr, insertTLI, true);
 
        /*
         * If we determined that we need to write data, but somebody else
@@ -9196,17 +9211,16 @@ CreateCheckPoint(int flags)
        /*
         * An end-of-recovery checkpoint is created before anyone is allowed to
         * write WAL. To allow us to write the checkpoint record, temporarily
-        * enable XLogInsertAllowed.  (This also ensures ThisTimeLineID is
-        * initialized, which we need here and in AdvanceXLInsertBuffer.)
+        * enable XLogInsertAllowed.
         */
        if (flags & CHECKPOINT_END_OF_RECOVERY)
                oldXLogAllowed = LocalSetXLogInsertAllowed();
 
-       checkPoint.ThisTimeLineID = ThisTimeLineID;
+       checkPoint.ThisTimeLineID = XLogCtl->ThisTimeLineID;
        if (flags & CHECKPOINT_END_OF_RECOVERY)
                checkPoint.PrevTimeLineID = XLogCtl->PrevTimeLineID;
        else
-               checkPoint.PrevTimeLineID = ThisTimeLineID;
+               checkPoint.PrevTimeLineID = checkPoint.ThisTimeLineID;
 
        checkPoint.fullPageWrites = Insert->fullPageWrites;
 
@@ -9463,14 +9477,15 @@ CreateCheckPoint(int flags)
                KeepLogSeg(recptr, &_logSegNo);
        }
        _logSegNo--;
-       RemoveOldXlogFiles(_logSegNo, RedoRecPtr, recptr, ThisTimeLineID);
+       RemoveOldXlogFiles(_logSegNo, RedoRecPtr, recptr,
+                                          checkPoint.ThisTimeLineID);
 
        /*
         * Make more log segments if needed.  (Do this after recycling old log
         * segments, since that may supply some of the needed files.)
         */
        if (!shutdown)
-               PreallocXlogFiles(recptr, ThisTimeLineID);
+               PreallocXlogFiles(recptr, checkPoint.ThisTimeLineID);
 
        /*
         * Truncate pg_subtrans if possible.  We can throw away all data before
@@ -9516,7 +9531,7 @@ CreateEndOfRecoveryRecord(void)
        xlrec.end_time = GetCurrentTimestamp();
 
        WALInsertLockAcquireExclusive();
-       xlrec.ThisTimeLineID = ThisTimeLineID;
+       xlrec.ThisTimeLineID = XLogCtl->ThisTimeLineID;
        xlrec.PrevTimeLineID = XLogCtl->PrevTimeLineID;
        WALInsertLockRelease();
 
@@ -9535,7 +9550,7 @@ CreateEndOfRecoveryRecord(void)
        LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
        ControlFile->time = (pg_time_t) time(NULL);
        ControlFile->minRecoveryPoint = recptr;
-       ControlFile->minRecoveryPointTLI = ThisTimeLineID;
+       ControlFile->minRecoveryPointTLI = xlrec.ThisTimeLineID;
        UpdateControlFile();
        LWLockRelease(ControlFileLock);
 
@@ -9858,9 +9873,8 @@ CreateRestartPoint(int flags)
        /*
         * Try to recycle segments on a useful timeline. If we've been promoted
         * since the beginning of this restartpoint, use the new timeline chosen
-        * at end of recovery (RecoveryInProgress() sets ThisTimeLineID in that
-        * case). If we're still in recovery, use the timeline we're currently
-        * replaying.
+        * at end of recovery.  If we're still in recovery, use the timeline we're
+        * currently replaying.
         *
         * There is no guarantee that the WAL segments will be useful on the
         * current timeline; if recovery proceeds to a new timeline right after
@@ -9868,25 +9882,16 @@ CreateRestartPoint(int flags)
         * and will go wasted until recycled on the next restartpoint. We'll live
         * with that.
         */
-       if (RecoveryInProgress())
-               ThisTimeLineID = replayTLI;
+       if (!RecoveryInProgress())
+               replayTLI = XLogCtl->ThisTimeLineID;
 
-       RemoveOldXlogFiles(_logSegNo, RedoRecPtr, endptr, ThisTimeLineID);
+       RemoveOldXlogFiles(_logSegNo, RedoRecPtr, endptr, replayTLI);
 
        /*
         * Make more log segments if needed.  (Do this after recycling old log
         * segments, since that may supply some of the needed files.)
         */
-       PreallocXlogFiles(endptr, ThisTimeLineID);
-
-       /*
-        * ThisTimeLineID is normally not set when we're still in recovery.
-        * However, recycling/preallocating segments above needed ThisTimeLineID
-        * to determine which timeline to install the segments on. Reset it now,
-        * to restore the normal state of affairs for debugging purposes.
-        */
-       if (RecoveryInProgress())
-               ThisTimeLineID = 0;
+       PreallocXlogFiles(endptr, replayTLI);
 
        /*
         * Truncate pg_subtrans if possible.  We can throw away all data before
@@ -11792,7 +11797,12 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
                XLogBeginInsert();
                XLogRegisterData((char *) (&startpoint), sizeof(startpoint));
                stoppoint = XLogInsert(RM_XLOG_ID, XLOG_BACKUP_END);
-               stoptli = ThisTimeLineID;
+
+               /*
+                * Given that we're not in recovery, ThisTimeLineID is set and can't
+                * change, so we can read it without a lock.
+                */
+               stoptli = XLogCtl->ThisTimeLineID;
 
                /*
                 * Force a switch to a new xlog segment file, so that the backup is