*/
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
/*
* 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);
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);
{
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);
+}
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
* 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
{
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);