Thread

  1. [PATCH v6 3/3] Move code to apply one WAL record to a subroutine.

    Heikki Linnakangas <heikki.linnakangas@iki.fi> — 2021-09-16T08:07:45Z

    ---
     src/backend/access/transam/xlogrecovery.c | 283 +++++++++++-----------
     1 file changed, 148 insertions(+), 135 deletions(-)
    
    diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
    index e46215c2586..65edc7e1316 100644
    --- a/src/backend/access/transam/xlogrecovery.c
    +++ b/src/backend/access/transam/xlogrecovery.c
    @@ -363,6 +363,7 @@ static char recoveryStopName[MAXFNAMELEN];
     static bool recoveryStopAfter;
     
     /* prototypes for local functions */
    +static void ApplyWalRecord(XLogReaderState *xlogreader, XLogRecord *record);
     static void xlog_block_info(StringInfo buf, XLogReaderState *record);
     
     static void readRecoverySignalFile(void);
    @@ -1361,11 +1362,8 @@ PerformWalRecovery(void)
     
     	if (record != NULL)
     	{
    -		ErrorContextCallback errcallback;
     		TimestampTz xtime;
     		PGRUsage	ru0;
    -		XLogRecPtr	ReadRecPtr;
    -		XLogRecPtr	EndRecPtr;
     
     		pg_rusage_init(&ru0);
     
    @@ -1387,11 +1385,6 @@ PerformWalRecovery(void)
     		 */
     		do
     		{
    -			bool		switchedTLI = false;
    -
    -			ReadRecPtr = xlogreader->ReadRecPtr;
    -			EndRecPtr = xlogreader->EndRecPtr;
    -
     #ifdef WAL_DEBUG
     			if (XLOG_DEBUG ||
     				(rmid == RM_XACT_ID && trace_recovery_messages <= DEBUG2) ||
    @@ -1401,8 +1394,8 @@ PerformWalRecovery(void)
     
     				initStringInfo(&buf);
     				appendStringInfo(&buf, "REDO @ %X/%X; LSN %X/%X: ",
    -								 LSN_FORMAT_ARGS(ReadRecPtr),
    -								 LSN_FORMAT_ARGS(EndRecPtr));
    +								 LSN_FORMAT_ARGS(xlogreader->ReadRecPtr),
    +								 LSN_FORMAT_ARGS(xlogreader->EndRecPtr));
     				xlog_outrec(&buf, xlogreader);
     				appendStringInfoString(&buf, " - ");
     				xlog_outdesc(&buf, xlogreader);
    @@ -1457,132 +1450,10 @@ PerformWalRecovery(void)
     					recoveryPausesHere(false);
     			}
     
    -			/* Setup error traceback support for ereport() */
    -			errcallback.callback = rm_redo_error_callback;
    -			errcallback.arg = (void *) xlogreader;
    -			errcallback.previous = error_context_stack;
    -			error_context_stack = &errcallback;
    -
    -			/*
    -			 * ShmemVariableCache->nextXid must be beyond record's xid.
    -			 */
    -			AdvanceNextFullTransactionIdPastXid(record->xl_xid);
    -
    -			/*
    -			 * Before replaying this record, check if this record causes the
    -			 * current timeline to change. The record is already considered to
    -			 * be part of the new timeline, so we update ThisTimeLineID before
    -			 * replaying it. That's important so that replayEndTLI, which is
    -			 * recorded as the minimum recovery point's TLI if recovery stops
    -			 * after this record, is set correctly.
    -			 */
    -			if (record->xl_rmid == RM_XLOG_ID)
    -			{
    -				TimeLineID	newTLI = ThisTimeLineID;
    -				TimeLineID	prevTLI = ThisTimeLineID;
    -				uint8		info = record->xl_info & ~XLR_INFO_MASK;
    -
    -				if (info == XLOG_CHECKPOINT_SHUTDOWN)
    -				{
    -					CheckPoint	checkPoint;
    -
    -					memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint));
    -					newTLI = checkPoint.ThisTimeLineID;
    -					prevTLI = checkPoint.PrevTimeLineID;
    -				}
    -				else if (info == XLOG_END_OF_RECOVERY)
    -				{
    -					xl_end_of_recovery xlrec;
    -
    -					memcpy(&xlrec, XLogRecGetData(xlogreader), sizeof(xl_end_of_recovery));
    -					newTLI = xlrec.ThisTimeLineID;
    -					prevTLI = xlrec.PrevTimeLineID;
    -				}
    -
    -				if (newTLI != ThisTimeLineID)
    -				{
    -					/* Check that it's OK to switch to this TLI */
    -					checkTimeLineSwitch(EndRecPtr, newTLI, prevTLI);
    -
    -					/* Following WAL records should be run with new TLI */
    -					ThisTimeLineID = newTLI;
    -					switchedTLI = true;
    -				}
    -			}
    -
    -			/*
    -			 * Update shared replayEndRecPtr before replaying this record, so
    -			 * that XLogFlush will update minRecoveryPoint correctly.
    -			 */
    -			SpinLockAcquire(&XLogRecCtl->info_lck);
    -			XLogRecCtl->replayEndRecPtr = EndRecPtr;
    -			XLogRecCtl->replayEndTLI = ThisTimeLineID;
    -			SpinLockRelease(&XLogRecCtl->info_lck);
    -
    -			/*
    -			 * If we are attempting to enter Hot Standby mode, process XIDs we
    -			 * see
    -			 */
    -			if (standbyState >= STANDBY_INITIALIZED &&
    -				TransactionIdIsValid(record->xl_xid))
    -				RecordKnownAssignedTransactionIds(record->xl_xid);
    -
    -			/* Now apply the WAL record itself */
    -			RmgrTable[record->xl_rmid].rm_redo(xlogreader);
    -
    -			/*
    -			 * After redo, check whether the backup pages associated with the
    -			 * WAL record are consistent with the existing pages. This check
    -			 * is done only if consistency check is enabled for this record.
    -			 */
    -			if ((record->xl_info & XLR_CHECK_CONSISTENCY) != 0)
    -				checkXLogConsistency(xlogreader);
    -
    -			/* Pop the error context stack */
    -			error_context_stack = errcallback.previous;
    -
    -			/*
    -			 * Update lastReplayedEndRecPtr after this record has been
    -			 * successfully replayed.
    -			 */
    -			SpinLockAcquire(&XLogRecCtl->info_lck);
    -			XLogRecCtl->lastReplayedEndRecPtr = EndRecPtr;
    -			XLogRecCtl->lastReplayedTLI = ThisTimeLineID;
    -			SpinLockRelease(&XLogRecCtl->info_lck);
    -
    -			/* Also remember its starting position. */
    -			LastReplayedReadRecPtr = ReadRecPtr;
    -
     			/*
    -			 * If rm_redo called XLogRequestWalReceiverReply, then we wake up
    -			 * the receiver so that it notices the updated
    -			 * lastReplayedEndRecPtr and sends a reply to the primary.
    +			 * Apply the record
     			 */
    -			if (doRequestWalReceiverReply)
    -			{
    -				doRequestWalReceiverReply = false;
    -				WalRcvForceReply();
    -			}
    -
    -			/* Allow read-only connections if we're consistent now */
    -			CheckRecoveryConsistency();
    -
    -			/* Is this a timeline switch? */
    -			if (switchedTLI)
    -			{
    -				/*
    -				 * Before we continue on the new timeline, clean up any
    -				 * (possibly bogus) future WAL segments on the old timeline.
    -				 */
    -				RemoveNonParentXlogFiles(EndRecPtr, ThisTimeLineID);
    -
    -				/*
    -				 * Wake up any walsenders to notice that we are on a new
    -				 * timeline.
    -				 */
    -				if (AllowCascadeReplication())
    -					WalSndWakeup();
    -			}
    +			ApplyWalRecord(xlogreader, record);
     
     			/* Exit loop if we reached inclusive recovery target */
     			if (recoveryStopsAfter(xlogreader))
    @@ -1641,7 +1512,7 @@ PerformWalRecovery(void)
     
     		ereport(LOG,
     				(errmsg("redo done at %X/%X system usage: %s",
    -						LSN_FORMAT_ARGS(ReadRecPtr),
    +						LSN_FORMAT_ARGS(xlogreader->ReadRecPtr),
     						pg_rusage_show(&ru0))));
     		xtime = GetLatestXTime();
     		if (xtime)
    @@ -1670,6 +1541,148 @@ PerformWalRecovery(void)
     				(errmsg("recovery ended before configured recovery target was reached")));
     }
     
    +/*
    + * Subroutine of PerformWalRecovery, to apply one WAL record.
    + */
    +static void
    +ApplyWalRecord(XLogReaderState *xlogreader, XLogRecord *record)
    +{
    +	XLogRecPtr	ReadRecPtr;
    +	XLogRecPtr	EndRecPtr;
    +	ErrorContextCallback errcallback;
    +	bool		switchedTLI = false;
    +
    +	ReadRecPtr = xlogreader->ReadRecPtr;
    +	EndRecPtr = xlogreader->EndRecPtr;
    +
    +	/* Setup error traceback support for ereport() */
    +	errcallback.callback = rm_redo_error_callback;
    +	errcallback.arg = (void *) xlogreader;
    +	errcallback.previous = error_context_stack;
    +	error_context_stack = &errcallback;
    +
    +	/*
    +	 * ShmemVariableCache->nextXid must be beyond record's xid.
    +	 */
    +	AdvanceNextFullTransactionIdPastXid(record->xl_xid);
    +
    +	/*
    +	 * Before replaying this record, check if this record causes the
    +	 * current timeline to change. The record is already considered to
    +	 * be part of the new timeline, so we update ThisTimeLineID before
    +	 * replaying it. That's important so that replayEndTLI, which is
    +	 * recorded as the minimum recovery point's TLI if recovery stops
    +	 * after this record, is set correctly.
    +	 */
    +	if (record->xl_rmid == RM_XLOG_ID)
    +	{
    +		TimeLineID	newTLI = ThisTimeLineID;
    +		TimeLineID	prevTLI = ThisTimeLineID;
    +		uint8		info = record->xl_info & ~XLR_INFO_MASK;
    +
    +		if (info == XLOG_CHECKPOINT_SHUTDOWN)
    +		{
    +			CheckPoint	checkPoint;
    +
    +			memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint));
    +			newTLI = checkPoint.ThisTimeLineID;
    +			prevTLI = checkPoint.PrevTimeLineID;
    +		}
    +		else if (info == XLOG_END_OF_RECOVERY)
    +		{
    +			xl_end_of_recovery xlrec;
    +
    +			memcpy(&xlrec, XLogRecGetData(xlogreader), sizeof(xl_end_of_recovery));
    +			newTLI = xlrec.ThisTimeLineID;
    +			prevTLI = xlrec.PrevTimeLineID;
    +		}
    +
    +		if (newTLI != ThisTimeLineID)
    +		{
    +			/* Check that it's OK to switch to this TLI */
    +			checkTimeLineSwitch(EndRecPtr, newTLI, prevTLI);
    +
    +			/* Following WAL records should be run with new TLI */
    +			ThisTimeLineID = newTLI;
    +			switchedTLI = true;
    +		}
    +	}
    +
    +	/*
    +	 * Update shared replayEndRecPtr before replaying this record, so
    +	 * that XLogFlush will update minRecoveryPoint correctly.
    +	 */
    +	SpinLockAcquire(&XLogRecCtl->info_lck);
    +	XLogRecCtl->replayEndRecPtr = EndRecPtr;
    +	XLogRecCtl->replayEndTLI = ThisTimeLineID;
    +	SpinLockRelease(&XLogRecCtl->info_lck);
    +
    +	/*
    +	 * If we are attempting to enter Hot Standby mode, process XIDs we
    +	 * see
    +	 */
    +	if (standbyState >= STANDBY_INITIALIZED &&
    +		TransactionIdIsValid(record->xl_xid))
    +		RecordKnownAssignedTransactionIds(record->xl_xid);
    +
    +	/* Now apply the WAL record itself */
    +	RmgrTable[record->xl_rmid].rm_redo(xlogreader);
    +
    +	/*
    +	 * After redo, check whether the backup pages associated with the
    +	 * WAL record are consistent with the existing pages. This check
    +	 * is done only if consistency check is enabled for this record.
    +	 */
    +	if ((record->xl_info & XLR_CHECK_CONSISTENCY) != 0)
    +		checkXLogConsistency(xlogreader);
    +
    +	/* Pop the error context stack */
    +	error_context_stack = errcallback.previous;
    +
    +	/*
    +	 * Update lastReplayedEndRecPtr after this record has been
    +	 * successfully replayed.
    +	 */
    +	SpinLockAcquire(&XLogRecCtl->info_lck);
    +	XLogRecCtl->lastReplayedEndRecPtr = EndRecPtr;
    +	XLogRecCtl->lastReplayedTLI = ThisTimeLineID;
    +	SpinLockRelease(&XLogRecCtl->info_lck);
    +
    +	/* Also remember its starting position. */
    +	LastReplayedReadRecPtr = ReadRecPtr;
    +
    +	/*
    +	 * If rm_redo called XLogRequestWalReceiverReply, then we wake up
    +	 * the receiver so that it notices the updated
    +	 * lastReplayedEndRecPtr and sends a reply to the primary.
    +	 */
    +	if (doRequestWalReceiverReply)
    +	{
    +		doRequestWalReceiverReply = false;
    +		WalRcvForceReply();
    +	}
    +
    +	/* Allow read-only connections if we're consistent now */
    +	CheckRecoveryConsistency();
    +
    +	/* Is this a timeline switch? */
    +	if (switchedTLI)
    +	{
    +		/*
    +		 * Before we continue on the new timeline, clean up any
    +		 * (possibly bogus) future WAL segments on the old timeline.
    +		 */
    +		RemoveNonParentXlogFiles(EndRecPtr, ThisTimeLineID);
    +
    +		/*
    +		 * Wake up any walsenders to notice that we are on a new
    +		 * timeline.
    +		 */
    +		if (AllowCascadeReplication())
    +			WalSndWakeup();
    +	}
    +}
    +
     /*
      * Error context callback for errors occurring during rm_redo().
      */
    -- 
    2.30.2
    
    
    --------------7E727ABC31D380A53E56FBBC--