*/
Latch recoveryWakeupLatch;
+ /*
+ * WALWriterLatch is used to wake up the WALWriter to write some WAL.
+ */
+ Latch WALWriterLatch;
+
/*
* During recovery, we keep a copy of the latest checkpoint record here.
* Used by the background writer when it wants to create a restartpoint.
}
/*
- * Record the LSN for an asynchronous transaction commit/abort.
+ * Record the LSN for an asynchronous transaction commit/abort
+ * and nudge the WALWriter if there is a complete page to write.
* (This should not be called for for synchronous commits.)
*/
void
XLogSetAsyncXactLSN(XLogRecPtr asyncXactLSN)
{
+ XLogRecPtr WriteRqstPtr = asyncXactLSN;
+
/* use volatile pointer to prevent code rearrangement */
volatile XLogCtlData *xlogctl = XLogCtl;
SpinLockAcquire(&xlogctl->info_lck);
+ LogwrtResult = xlogctl->LogwrtResult;
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 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.
+ */
+ SetLatch(&XLogCtl->WALWriterLatch);
}
/*
XLogCtl->Insert.currpage = (XLogPageHeader) (XLogCtl->pages);
SpinLockInit(&XLogCtl->info_lck);
InitSharedLatch(&XLogCtl->recoveryWakeupLatch);
+ InitSharedLatch(&XLogCtl->WALWriterLatch);
/*
* If we are not in bootstrap mode, pg_control should already exist. Read
{
SetLatch(&XLogCtl->recoveryWakeupLatch);
}
+
+/*
+ * Manage the WALWriterLatch
+ */
+Latch *
+WALWriterLatch(void)
+{
+ return &XLogCtl->WALWriterLatch;
+}
*
* Note that as with the bgwriter for shared buffers, regular backends are
* still empowered to issue WAL writes and fsyncs when the walwriter doesn't
- * keep up.
+ * keep up. This means that the WALWriter is not an essential process and
+ * can shutdown quickly when requested.
*
* Because the walwriter's cycle is directly linked to the maximum delay
* before async-commit transactions are guaranteed committed, it's probably
static void WalSigHupHandler(SIGNAL_ARGS);
static void WalShutdownHandler(SIGNAL_ARGS);
-
/*
* Main entry point for walwriter process
*
sigjmp_buf local_sigjmp_buf;
MemoryContext walwriter_context;
+ InitLatch(WALWriterLatch()); /* initialize latch used in main loop */
+
/*
* If possible, make this process a group leader, so that the postmaster
* can signal any child processes too. (walwriter probably never has any
*/
for (;;)
{
- long udelay;
+ ResetLatch(WALWriterLatch());
/*
* Emergency bailout if postmaster has died. This is to avoid the
*/
XLogBackgroundFlush();
- /*
- * Delay until time to do something more, but fall out of delay
- * reasonably quickly if signaled.
- */
- udelay = WalWriterDelay * 1000L;
- while (udelay > 999999L)
- {
- if (got_SIGHUP || shutdown_requested)
- break;
- pg_usleep(1000000L);
- udelay -= 1000000L;
- }
- if (!(got_SIGHUP || shutdown_requested))
- pg_usleep(udelay);
+ (void) WaitLatch(WALWriterLatch(),
+ WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ WalWriterDelay /* ms */);
}
}
WalSigHupHandler(SIGNAL_ARGS)
{
got_SIGHUP = true;
+ SetLatch(WALWriterLatch());
}
/* SIGTERM: set flag to exit normally */
WalShutdownHandler(SIGNAL_ARGS)
{
shutdown_requested = true;
+ SetLatch(WALWriterLatch());
}
#include "datatype/timestamp.h"
#include "lib/stringinfo.h"
#include "storage/buf.h"
+#include "storage/latch.h"
#include "utils/pg_crc.h"
/*
extern bool CheckPromoteSignal(void);
extern void WakeupRecovery(void);
+extern Latch *WALWriterLatch(void);
/*
* Starting/stopping a base backup