From 55e99daad99ec2f4fae907938b5cf38a2afe11dd Mon Sep 17 00:00:00 2001 From: Amul Sul Date: Thu, 30 Sep 2021 06:29:06 -0400 Subject: [PATCH v43 2/6] 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 EndOfLog shared memory values. XLogAcceptWrites() accepts two argument as EndOfLogTLI and EndOfLog which are local to StartupXLOG(). Both of these are also exported into shared memory since non of the existing shared memory variable matches exactly with these values. Also, make sure to use a volatile pointer to access XLogCtl to read the latest shared variable values. --- src/backend/access/transam/xlog.c | 107 +++++++++++++++++++++++------- 1 file changed, 84 insertions(+), 23 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index e523eb40b9a..e6fed15516c 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -660,6 +660,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). @@ -709,6 +716,21 @@ 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; + + /* + * Determines an endpoint that we consider a valid portion of WAL when + * server startup. It is invalid during recovery and does not change once + * set. + */ + XLogRecPtr endOfLog; + TimeLineID endOfLogTLI; + /* * timestamp of when we started replaying the current chunk of WAL data, * only relevant for replication or archive recovery @@ -882,9 +904,7 @@ static void readRecoverySignalFile(void); static void validateRecoveryParameters(void); static void exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog, TimeLineID newTLI); -static void CleanupAfterArchiveRecovery(TimeLineID EndOfLogTLI, - XLogRecPtr EndOfLog, - TimeLineID newTLI); +static void CleanupAfterArchiveRecovery(void); static bool recoveryStopsBefore(XLogReaderState *record); static bool recoveryStopsAfter(XLogReaderState *record); static char *getRecoveryStopReason(void); @@ -939,8 +959,7 @@ static XLogRecord *ReadRecord(XLogReaderState *xlogreader, int emode, bool fetching_ckpt, TimeLineID replayTLI); static void CheckRecoveryConsistency(void); -static bool XLogAcceptWrites(TimeLineID EndOfLogTLI, XLogRecPtr EndOfLog, - TimeLineID newTLI); +static bool XLogAcceptWrites(void); static bool PerformRecoveryXLogAction(void); static XLogRecord *ReadCheckpointRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, int whichChkpt, bool report, @@ -5599,6 +5618,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 @@ -5789,9 +5813,17 @@ exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog, TimeLineID newTLI) * Perform cleanup actions at the conclusion of archive recovery. */ static void -CleanupAfterArchiveRecovery(TimeLineID EndOfLogTLI, XLogRecPtr EndOfLog, - TimeLineID newTLI) +CleanupAfterArchiveRecovery(void) { + /* + * use volatile pointer to make sure we make a fresh read of the + * shared variable. + */ + volatile XLogCtlData *xlogctl = XLogCtl; + + XLogRecPtr EndOfLog = xlogctl->endOfLog; + TimeLineID EndOfLogTLI = xlogctl->endOfLogTLI; + /* * Execute the recovery_end_command, if any. */ @@ -5809,7 +5841,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. */ - RemoveNonParentXlogFiles(EndOfLog, newTLI); + RemoveNonParentXlogFiles(EndOfLog, xlogctl->InsertTimeLineID); /* * If the switch happened in the middle of a segment, what to do with the @@ -8038,6 +8070,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; } /* @@ -8106,6 +8148,13 @@ StartupXLOG(void) XLogCtl->lastSegSwitchTime = (pg_time_t) time(NULL); XLogCtl->lastSegSwitchLSN = EndOfLog; + /* + * Store EndOfLog and EndOfLogTLI into shared memory to share with other + * processes. + */ + XLogCtl->endOfLog = EndOfLog; + XLogCtl->endOfLogTLI = EndOfLogTLI; + /* also initialize latestCompletedXid, to nextXid - 1 */ LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); ShmemVariableCache->latestCompletedXid = ShmemVariableCache->nextXid; @@ -8136,8 +8185,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, newTLI); + promoted = XLogAcceptWrites(); /* * All done with end-of-recovery actions. @@ -8197,30 +8253,35 @@ StartupXLOG(void) * Prepare to accept WAL writes. */ static bool -XLogAcceptWrites(TimeLineID EndOfLogTLI, XLogRecPtr EndOfLog, - TimeLineID newTLI) +XLogAcceptWrites(void) { bool promoted = false; - XLogCtlInsert *Insert = &XLogCtl->Insert; + + /* + * use volatile pointer to make sure we make a fresh read of the + * shared variable. + */ + volatile XLogCtlData *xlogctl = XLogCtl; /* Enable WAL writes for this backend only. */ LocalSetXLogInsertAllowed(); /* If necessary, write overwrite-contrecord before doing anything else */ - if (!XLogRecPtrIsInvalid(abortedRecPtr)) + if (!XLogRecPtrIsInvalid(xlogctl->SharedAbortedRecPtr)) { + /* Restore values */ + abortedRecPtr = xlogctl->SharedAbortedRecPtr; + missingContrecPtr = xlogctl->endOfLog; + Assert(!XLogRecPtrIsInvalid(missingContrecPtr)); CreateOverwriteContrecordRecord(abortedRecPtr); + + xlogctl->SharedAbortedRecPtr = InvalidXLogRecPtr; abortedRecPtr = InvalidXLogRecPtr; missingContrecPtr = 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(); /* @@ -8232,7 +8293,7 @@ XLogAcceptWrites(TimeLineID EndOfLogTLI, XLogRecPtr EndOfLog, * need a lock to access this, since this can't change any more by the time * we reach this code. */ - if (!XLogRecPtrIsInvalid(XLogCtl->lastReplayedEndRecPtr)) + if (!XLogRecPtrIsInvalid(xlogctl->lastReplayedEndRecPtr)) promoted = PerformRecoveryXLogAction(); /* @@ -8243,7 +8304,7 @@ XLogAcceptWrites(TimeLineID EndOfLogTLI, XLogRecPtr EndOfLog, /* If this is archive recovery, perform post-recovery cleanup actions. */ if (ArchiveRecoveryRequested) - CleanupAfterArchiveRecovery(EndOfLogTLI, EndOfLog, newTLI); + CleanupAfterArchiveRecovery(); /* * Local WAL inserts enabled, so it's time to finish initialization of @@ -8378,8 +8439,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