aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/transam/xlog.c48
-rw-r--r--src/backend/postmaster/walwriter.c18
-rw-r--r--src/include/access/xlog.h1
3 files changed, 60 insertions, 7 deletions
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 6d3a4cd3dfe..d3650bdf051 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -427,6 +427,13 @@ typedef struct XLogCtlData
bool SharedHotStandbyActive;
/*
+ * WalWriterSleeping indicates whether the WAL writer is currently in
+ * low-power mode (and hence should be nudged if an async commit occurs).
+ * Protected by info_lck.
+ */
+ bool WalWriterSleeping;
+
+ /*
* recoveryWakeupLatch is used to wake up the startup process to continue
* WAL replay, if it is waiting for WAL to arrive or failover trigger file
* to appear.
@@ -1903,32 +1910,44 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch)
/*
* Record the LSN for an asynchronous transaction commit/abort
- * and nudge the WALWriter if there is a complete page to write.
+ * and nudge the WALWriter if there is work for it to do.
* (This should not be called for synchronous commits.)
*/
void
XLogSetAsyncXactLSN(XLogRecPtr asyncXactLSN)
{
XLogRecPtr WriteRqstPtr = asyncXactLSN;
+ bool sleeping;
/* use volatile pointer to prevent code rearrangement */
volatile XLogCtlData *xlogctl = XLogCtl;
SpinLockAcquire(&xlogctl->info_lck);
LogwrtResult = xlogctl->LogwrtResult;
+ sleeping = xlogctl->WalWriterSleeping;
if (XLByteLT(xlogctl->asyncXactLSN, asyncXactLSN))
xlogctl->asyncXactLSN = asyncXactLSN;
SpinLockRelease(&xlogctl->info_lck);
- /* back off to last completed page boundary */
- WriteRqstPtr.xrecoff -= WriteRqstPtr.xrecoff % XLOG_BLCKSZ;
+ /*
+ * If the WALWriter is sleeping, we should kick it to make it come out of
+ * low-power mode. Otherwise, determine whether there's a full page of
+ * WAL available to write.
+ */
+ if (!sleeping)
+ {
+ /* back off to last completed page boundary */
+ WriteRqstPtr.xrecoff -= WriteRqstPtr.xrecoff % XLOG_BLCKSZ;
- /* if we have already flushed that far, we're done */
- if (XLByteLE(WriteRqstPtr, LogwrtResult.Flush))
- return;
+ /* if we have already flushed that far, we're done */
+ if (XLByteLE(WriteRqstPtr, LogwrtResult.Flush))
+ return;
+ }
/*
- * Nudge the WALWriter if we have a full page of WAL to write.
+ * Nudge the WALWriter: it has a full page of WAL to write, or we want
+ * it to come out of low-power mode so that this async commit will reach
+ * disk within the expected amount of time.
*/
if (ProcGlobal->walwriterLatch)
SetLatch(ProcGlobal->walwriterLatch);
@@ -5100,6 +5119,7 @@ XLOGShmemInit(void)
XLogCtl->XLogCacheBlck = XLOGbuffers - 1;
XLogCtl->SharedRecoveryInProgress = true;
XLogCtl->SharedHotStandbyActive = false;
+ XLogCtl->WalWriterSleeping = false;
XLogCtl->Insert.currpage = (XLogPageHeader) (XLogCtl->pages);
SpinLockInit(&XLogCtl->info_lck);
InitSharedLatch(&XLogCtl->recoveryWakeupLatch);
@@ -10479,3 +10499,17 @@ WakeupRecovery(void)
{
SetLatch(&XLogCtl->recoveryWakeupLatch);
}
+
+/*
+ * Update the WalWriterSleeping flag.
+ */
+void
+SetWalWriterSleeping(bool sleeping)
+{
+ /* use volatile pointer to prevent code rearrangement */
+ volatile XLogCtlData *xlogctl = XLogCtl;
+
+ SpinLockAcquire(&xlogctl->info_lck);
+ xlogctl->WalWriterSleeping = sleeping;
+ SpinLockRelease(&xlogctl->info_lck);
+}
diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c
index cd41dbbc8c3..733d01fd5b3 100644
--- a/src/backend/postmaster/walwriter.c
+++ b/src/backend/postmaster/walwriter.c
@@ -99,6 +99,7 @@ WalWriterMain(void)
sigjmp_buf local_sigjmp_buf;
MemoryContext walwriter_context;
int left_till_hibernate;
+ bool hibernating;
/*
* If possible, make this process a group leader, so that the postmaster
@@ -230,6 +231,8 @@ WalWriterMain(void)
* Reset hibernation state after any error.
*/
left_till_hibernate = LOOPS_UNTIL_HIBERNATE;
+ hibernating = false;
+ SetWalWriterSleeping(false);
/*
* Advertise our latch that backends can use to wake us up while we're
@@ -244,6 +247,21 @@ WalWriterMain(void)
{
long cur_timeout;
+ /*
+ * Advertise whether we might hibernate in this cycle. We do this
+ * before resetting the latch to ensure that any async commits will
+ * see the flag set if they might possibly need to wake us up, and
+ * that we won't miss any signal they send us. (If we discover work
+ * to do in the last cycle before we would hibernate, the global flag
+ * will be set unnecessarily, but little harm is done.) But avoid
+ * touching the global flag if it doesn't need to change.
+ */
+ if (hibernating != (left_till_hibernate <= 1))
+ {
+ hibernating = (left_till_hibernate <= 1);
+ SetWalWriterSleeping(hibernating);
+ }
+
/* Clear any already-pending wakeups */
ResetLatch(&MyProc->procLatch);
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 129712e7b9c..df5f232eeea 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -316,6 +316,7 @@ extern TimeLineID GetRecoveryTargetTLI(void);
extern bool CheckPromoteSignal(void);
extern void WakeupRecovery(void);
+extern void SetWalWriterSleeping(bool sleeping);
/*
* Starting/stopping a base backup