From 1173a55fab286cd1a8eb9ae3ae35fe9c2ad5cd0f Mon Sep 17 00:00:00 2001 From: Amul Sul Date: Thu, 30 Sep 2021 06:29:06 -0400 Subject: [PATCH v39 4/4] Remove dependencies on startup-process specifical variables. To make XLogAcceptWrites(), need to dependency on few global and local variable spcific to startup process. Global variables are abortedRecPtr, missingContrecPtr, ArchiveRecoveryRequested and LocalPromoteIsTriggered, whereas LocalPromoteIsTriggered can be accessed in any other process using existing PromoteIsTriggered(). abortedRecPtr & ArchiveRecoveryRequested is made accessible by copying into shared memory. missingContrecPtr can get from the existing shared memory values where it get stored through EndOfLog if valid. XLogAcceptWrites() accepts two argument as EndOfLogTLI and EndOfLog which are local to StartupXLOG(). Instead of passing as an argument XLogCtl->replayEndTLI and XLogCtl->lastSegSwitchLSN from the shared memory can be used as an replacement to EndOfLogTLI and EndOfLog respectively. XLogCtl->lastSegSwitchLSN is not going to change until we use it. That changes only when the current WAL segment gets full which never going to happen because of two reasons, first WAL writes are disabled for other processes until XLogAcceptWrites() finishes and other reasons before use of lastSegSwitchLSN, XLogAcceptWrites() is writes fix size wal records as full-page write and record for either recovery end or checkpoint which not going to fill up the 16MB wal segment. EndOfLogTLI in the StartupXLOG() is the timeline ID of the last record that xlogreader reads, but this xlogreader was simply re-fetching the last record which we have replied in redo loop if it was in recovery, if not in recovery, we don't need to worry since this value is needed only in case of ArchiveRecoveryRequested = true, which implicitly forces redo and sets XLogCtl->replayEndTLI value. --- src/backend/access/transam/xlog.c | 83 ++++++++++++++++++++++++------- 1 file changed, 64 insertions(+), 19 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index e5375cd1bb5..5b12addc228 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -668,6 +668,13 @@ typedef struct XLogCtlData */ bool SharedPromoteIsTriggered; + /* + * SharedArchiveRecoveryRequested exports the value of the + * ArchiveRecoveryRequested flag to be share which is otherwise valid only + * in the startup process. + */ + bool SharedArchiveRecoveryRequested; + /* * WalWriterSleeping indicates whether the WAL writer is currently in * low-power mode (and hence should be nudged if an async commit occurs). @@ -717,6 +724,13 @@ typedef struct XLogCtlData /* timestamp of last COMMIT/ABORT record replayed (or being replayed) */ TimestampTz recoveryLastXTime; + /* + * SharedAbortedRecPtr exports abortedRecPtr to be shared with another + * process to write OVERWRITE_CONTRECORD message, if WAL writes are not + * permitted in the current process which reads that. + */ + XLogRecPtr SharedAbortedRecPtr; + /* * timestamp of when we started replaying the current chunk of WAL data, * only relevant for replication or archive recovery @@ -889,8 +903,7 @@ static MemoryContext walDebugCxt = NULL; static void readRecoverySignalFile(void); static void validateRecoveryParameters(void); static void exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog); -static void CleanupAfterArchiveRecovery(TimeLineID EndOfLogTLI, - XLogRecPtr EndOfLog); +static void CleanupAfterArchiveRecovery(void); static bool recoveryStopsBefore(XLogReaderState *record); static bool recoveryStopsAfter(XLogReaderState *record); static char *getRecoveryStopReason(void); @@ -939,7 +952,7 @@ static void UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force); static XLogRecord *ReadRecord(XLogReaderState *xlogreader, int emode, bool fetching_ckpt); static void CheckRecoveryConsistency(void); -static bool XLogAcceptWrites(TimeLineID EndOfLogTLI, XLogRecPtr EndOfLog); +static bool XLogAcceptWrites(void); static bool PerformRecoveryXLogAction(void); static XLogRecord *ReadCheckpointRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, int whichChkpt, bool report); @@ -5267,7 +5280,9 @@ XLOGShmemInit(void) XLogCtl->SharedHotStandbyActive = false; XLogCtl->InstallXLogFileSegmentActive = false; XLogCtl->SharedPromoteIsTriggered = false; + XLogCtl->SharedArchiveRecoveryRequested = false; XLogCtl->WalWriterSleeping = false; + XLogCtl->SharedAbortedRecPtr = InvalidXLogRecPtr; SpinLockInit(&XLogCtl->Insert.insertpos_lck); SpinLockInit(&XLogCtl->info_lck); @@ -5548,6 +5563,11 @@ readRecoverySignalFile(void) ereport(FATAL, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("standby mode is not supported by single-user servers"))); + + /* + * Remember archive recovery request in shared memory state. + */ + XLogCtl->SharedArchiveRecoveryRequested = ArchiveRecoveryRequested; } static void @@ -5739,8 +5759,10 @@ exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog) * Perform cleanup actions at the conclusion of archive recovery. */ static void -CleanupAfterArchiveRecovery(TimeLineID EndOfLogTLI, XLogRecPtr EndOfLog) +CleanupAfterArchiveRecovery(void) { + XLogRecPtr EndOfLog; + /* * Execute the recovery_end_command, if any. */ @@ -5757,6 +5779,7 @@ CleanupAfterArchiveRecovery(TimeLineID EndOfLogTLI, XLogRecPtr EndOfLog) * files containing garbage. In any case, they are not part of the new * timeline's history so we don't need them. */ + (void) GetLastSegSwitchData(&EndOfLog); RemoveNonParentXlogFiles(EndOfLog, ThisTimeLineID); /* @@ -5791,6 +5814,7 @@ CleanupAfterArchiveRecovery(TimeLineID EndOfLogTLI, XLogRecPtr EndOfLog) { char origfname[MAXFNAMELEN]; XLogSegNo endLogSegNo; + TimeLineID EndOfLogTLI = XLogCtl->replayEndTLI; XLByteToPrevSeg(EndOfLog, endLogSegNo, wal_segment_size); XLogFileName(origfname, EndOfLogTLI, endLogSegNo, wal_segment_size); @@ -7965,6 +7989,16 @@ StartupXLOG(void) { Assert(!XLogRecPtrIsInvalid(abortedRecPtr)); EndOfLog = missingContrecPtr; + + /* + * Remember broken record pointer in shared memory state. This process + * might unable to write an OVERWRITE_CONTRECORD message because of WAL + * write restriction. Storing in shared memory helps that get written + * later by another process as soon as WAL writing is enabled. + */ + XLogCtl->SharedAbortedRecPtr = abortedRecPtr; + abortedRecPtr = InvalidXLogRecPtr; + missingContrecPtr = InvalidXLogRecPtr; } /* @@ -8063,8 +8097,15 @@ StartupXLOG(void) } XLogReaderFree(xlogreader); + /* + * Update full_page_writes in shared memory, and later whenever wal write + * permitted, write an XLOG_FPW_CHANGE record before resource manager + * writes cleanup WAL records or checkpoint record is written. + */ + Insert->fullPageWrites = lastFullPageWrites; + /* Prepare to accept WAL writes. */ - promoted = XLogAcceptWrites(EndOfLogTLI, EndOfLog); + promoted = XLogAcceptWrites(); /* * All done with end-of-recovery actions. @@ -8124,7 +8165,7 @@ StartupXLOG(void) * Prepare to accept WAL writes. */ static bool -XLogAcceptWrites(TimeLineID EndOfLogTLI, XLogRecPtr EndOfLog) +XLogAcceptWrites(void) { bool promoted = false; int oldXLogAllowed; @@ -8132,20 +8173,24 @@ XLogAcceptWrites(TimeLineID EndOfLogTLI, XLogRecPtr EndOfLog) oldXLogAllowed = LocalSetXLogInsertAllowed(); /* If necessary, write overwrite-contrecord before doing anything else */ - if (!XLogRecPtrIsInvalid(abortedRecPtr)) + if (!XLogRecPtrIsInvalid(XLogCtl->SharedAbortedRecPtr)) { + /* + * Restore missingContrecPtr, needed to set + * XLP_FIRST_IS_OVERWRITE_CONTRECORD flag on the page header where + * overwrite-contrecord get written. See AdvanceXLInsertBuffer(). + * + * NB: We can safely use lastSegSwitchLSN to restore missingContrecPtr, + * which is never going to change until we reach here since there wasn't + * any wal write before. + */ + GetLastSegSwitchData(&missingContrecPtr); Assert(!XLogRecPtrIsInvalid(missingContrecPtr)); - CreateOverwriteContrecordRecord(abortedRecPtr); - abortedRecPtr = InvalidXLogRecPtr; - missingContrecPtr = InvalidXLogRecPtr; + CreateOverwriteContrecordRecord(XLogCtl->SharedAbortedRecPtr); + XLogCtl->SharedAbortedRecPtr = InvalidXLogRecPtr; } - /* - * Update full_page_writes in shared memory and write an XLOG_FPW_CHANGE - * record before resource manager writes cleanup WAL records or checkpoint - * record is written. - */ - Insert->fullPageWrites = lastFullPageWrites; + /* Write an XLOG_FPW_CHANGE record */ UpdateFullPageWrites(); /* @@ -8169,7 +8214,7 @@ XLogAcceptWrites(TimeLineID EndOfLogTLI, XLogRecPtr EndOfLog) /* If this is archive recovery, perform post-recovery cleanup actions. */ if (ArchiveRecoveryRequested) - CleanupAfterArchiveRecovery(EndOfLogTLI, EndOfLog); + CleanupAfterArchiveRecovery(); /* * Local WAL inserts enabled, so it's time to finish initialization of @@ -8304,8 +8349,8 @@ PerformRecoveryXLogAction(void) * a full checkpoint. A checkpoint is requested later, after we're fully out * of recovery mode and already accepting queries. */ - if (ArchiveRecoveryRequested && IsUnderPostmaster && - LocalPromoteIsTriggered) + if (XLogCtl->SharedArchiveRecoveryRequested && IsUnderPostmaster && + PromoteIsTriggered()) { promoted = true; -- 2.18.0