walwriter_latch_v1_2012_05_02.patch
application/octet-stream
Filename: walwriter_latch_v1_2012_05_02.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
Series: patch v1
| File | + | − |
|---|---|---|
| src/backend/access/transam/xlog.c | 16 | 17 |
| src/backend/postmaster/walwriter.c | 146 | 9 |
| src/backend/storage/lmgr/proc.c | 1 | 0 |
| src/include/access/xlog.h | 1 | 2 |
| src/include/storage/latch.h | 7 | 1 |
| src/include/storage/proc.h | 2 | 0 |
diff src/backend/access/transam/xlog.c
index 8d0aabf..e5adfab
*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
*************** typedef struct XLogCtlData
*** 434,444 ****
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.
*
--- 434,439 ----
*************** begin:;
*** 1213,1218 ****
--- 1208,1220 ----
END_CRIT_SECTION();
+ /*
+ * Now that we've gone through with inserting WAL, nudge the WALWriter,
+ * provoking a set number of iterations.
+ */
+ if (ProcGlobal->walwriterLatch)
+ SetLatch(ProcGlobal->walwriterLatch);
+
return RecPtr;
}
*************** XLogSetAsyncXactLSN(XLogRecPtr asyncXact
*** 1935,1941 ****
/*
* Nudge the WALWriter if we have a full page of WAL to write.
*/
! SetLatch(&XLogCtl->WALWriterLatch);
}
/*
--- 1937,1944 ----
/*
* Nudge the WALWriter if we have a full page of WAL to write.
*/
! if (ProcGlobal->walwriterLatch)
! SetLatch(ProcGlobal->walwriterLatch);
}
/*
*************** XLogFlush(XLogRecPtr record)
*** 2173,2188 ****
* case for async commits.)
*
* This routine is invoked periodically by the background walwriter process.
*/
! void
XLogBackgroundFlush(void)
{
XLogRecPtr WriteRqstPtr;
bool flexible = true;
/* XLOG doesn't need flushing during recovery */
if (RecoveryInProgress())
! return;
/* read LogwrtResult and update local state */
{
--- 2176,2194 ----
* case for async commits.)
*
* This routine is invoked periodically by the background walwriter process.
+ *
+ * Returns a value indicating if useful work was performed.
*/
! bool
XLogBackgroundFlush(void)
{
XLogRecPtr WriteRqstPtr;
bool flexible = true;
+ bool worked = false;
/* XLOG doesn't need flushing during recovery */
if (RecoveryInProgress())
! return false;
/* read LogwrtResult and update local state */
{
*************** XLogBackgroundFlush(void)
*** 2224,2230 ****
XLogFileClose();
}
}
! return;
}
#ifdef WAL_DEBUG
--- 2230,2236 ----
XLogFileClose();
}
}
! return false;
}
#ifdef WAL_DEBUG
*************** XLogBackgroundFlush(void)
*** 2247,2256 ****
--- 2253,2265 ----
WriteRqst.Write = WriteRqstPtr;
WriteRqst.Flush = WriteRqstPtr;
XLogWrite(WriteRqst, flexible, false);
+ worked = true;
}
LWLockRelease(WALWriteLock);
END_CRIT_SECTION();
+
+ return worked;
}
/*
*************** XLOGShmemInit(void)
*** 5101,5107 ****
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
--- 5110,5115 ----
*************** WakeupRecovery(void)
*** 10479,10490 ****
{
SetLatch(&XLogCtl->recoveryWakeupLatch);
}
-
- /*
- * Manage the WALWriterLatch
- */
- Latch *
- WALWriterLatch(void)
- {
- return &XLogCtl->WALWriterLatch;
- }
--- 10487,10489 ----
diff src/backend/postmaster/walwriter.c
index 08ef946..eb09359
*** a/src/backend/postmaster/walwriter.c
--- b/src/backend/postmaster/walwriter.c
***************
*** 54,59 ****
--- 54,60 ----
#include "storage/ipc.h"
#include "storage/lwlock.h"
#include "storage/pmsignal.h"
+ #include "storage/proc.h"
#include "storage/smgr.h"
#include "utils/guc.h"
#include "utils/hsearch.h"
***************
*** 67,81 ****
--- 68,93 ----
int WalWriterDelay = 200;
/*
+ * Number of loops before each nap is extended to a hibernation, and time to
+ * sleep between walwriter rounds when hibernating.
+ */
+ #define LOOPS_UNTIL_HIBERNATE 100
+ #define HIBERNATE_MS 10000
+
+ /*
* Flags set by interrupt handlers for later service in the main loop.
*/
static volatile sig_atomic_t got_SIGHUP = false;
static volatile sig_atomic_t shutdown_requested = false;
+ /* Prototypes for private functions */
+ static bool WalWriterNap(bool hibernating);
+
/* Signal handlers */
static void wal_quickdie(SIGNAL_ARGS);
static void WalSigHupHandler(SIGNAL_ARGS);
static void WalShutdownHandler(SIGNAL_ARGS);
+ static void walwriter_sigusr1_handler(SIGNAL_ARGS);
/*
* Main entry point for walwriter process
*************** WalWriterMain(void)
*** 88,95 ****
{
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
--- 100,107 ----
{
sigjmp_buf local_sigjmp_buf;
MemoryContext walwriter_context;
! int left_till_hibernate = LOOPS_UNTIL_HIBERNATE;
! bool hibernating;
/*
* If possible, make this process a group leader, so that the postmaster
*************** WalWriterMain(void)
*** 114,120 ****
pqsignal(SIGQUIT, wal_quickdie); /* hard crash time */
pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN);
! pqsignal(SIGUSR1, SIG_IGN); /* reserve for ProcSignal */
pqsignal(SIGUSR2, SIG_IGN); /* not used */
/*
--- 126,132 ----
pqsignal(SIGQUIT, wal_quickdie); /* hard crash time */
pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN);
! pqsignal(SIGUSR1, walwriter_sigusr1_handler);
pqsignal(SIGUSR2, SIG_IGN); /* not used */
/*
*************** WalWriterMain(void)
*** 218,229 ****
PG_SETMASK(&UnBlockSig);
/*
* Loop forever
*/
for (;;)
{
- ResetLatch(WALWriterLatch());
-
/*
* Emergency bailout if postmaster has died. This is to avoid the
* necessity for manual cleanup of all postmaster children.
--- 230,246 ----
PG_SETMASK(&UnBlockSig);
/*
+ * Advertise our latch that backends can use to wake us up while we're
+ * sleeping.
+ */
+ ProcGlobal->walwriterLatch = &MyProc->procLatch;
+
+ /*
* Loop forever
*/
+ hibernating = false;
for (;;)
{
/*
* Emergency bailout if postmaster has died. This is to avoid the
* necessity for manual cleanup of all postmaster children.
*************** WalWriterMain(void)
*** 248,261 ****
/*
* Do what we're here for...
*/
! XLogBackgroundFlush();
! (void) WaitLatch(WALWriterLatch(),
! WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
! WalWriterDelay /* ms */);
}
}
/* --------------------------------
* signal handler routines
--- 265,394 ----
/*
* Do what we're here for...
*/
! if (hibernating)
! ResetLatch(&MyProc->procLatch);
! /*
! * If XLogBackgroundFlush() found useful work to do, reset iterations
! * left until hibernation.
! */
! if (XLogBackgroundFlush())
! left_till_hibernate = LOOPS_UNTIL_HIBERNATE;
! else if (left_till_hibernate > 0)
! left_till_hibernate--;
!
! if (left_till_hibernate == 0 && !hibernating)
! {
! /*
! * XLogBackgroundFlush did nothing for a sufficient number of
! * iterations. Since there doesn't seem to be any work for the
! * walwriter to do, go into slower-paced "hibernation" mode, where
! * we sleep for much longer times than bgwriter_delay says. Fewer
! * wakeups saves electricity. If a backend inserts WAL, it will
! * wake us up by setting our latch.
! *
! * The latch is kept set during productive cycles where WAL is
! * written and/or synced, and only reset before going into a longer
! * sleep. That ensures that when there's a constant trickle of
! * activity, the SetLatch() calls that backends have to do will see
! * the latch as already set, and are not slowed down by having to
! * actually set the latch and signal us.
! */
! hibernating = true;
!
! /*
! * Take one more short nap and perform one more walwriter cycle -
! * control in another process might have reached XLogInsert() just
! * after we finished the previous walwriter cycle, while the latch
! * was still set. If we still find nothing to do after this cycle,
! * the next sleep will be longer.
! */
! WalWriterNap(false);
! continue;
! }
! else if (left_till_hibernate > 0 && hibernating)
! {
! /*
! * Woke up from hibernation, and may have found work to do. Set the
! * latch just in case it's not set yet (usually we wake up from
! * hibernation because a backend already set the latch, but not
! * necessarily).
! */
! SetLatch(&MyProc->procLatch);
! hibernating = false;
! }
!
! /*
! * If the latch is set, don't immediately go back to hibernation if no
! * work is performed in the first iteration.
! */
! if (WalWriterNap(hibernating))
! left_till_hibernate = LOOPS_UNTIL_HIBERNATE;
}
}
+ /*
+ * WalWriterNap -- Nap for the configured time or until a signal is received.
+ *
+ * If 'hibernating' is false, sleeps for wal_writer_delay milliseconds.
+ * Otherwise sleeps longer, but also wakes up if the process latch is set.
+ *
+ * Returns a value indicating if return was due to latch being set.
+ */
+ static bool
+ WalWriterNap(bool hibernating)
+ {
+ long udelay;
+ bool latch_set = false;
+
+ /*
+ * Nap for the configured time, or sleep for 10 seconds if there is no
+ * walwriter activity required.
+ *
+ * If there was no work to do in the previous LOOPS_UNTIL_HIBERNATE cycles,
+ * take a longer nap.
+ */
+ if (hibernating)
+ {
+ int res = WaitLatch(&MyProc->procLatch,
+ WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ HIBERNATE_MS);
+
+ /*
+ * Only do a quick return if timeout was reached (or postmaster died)
+ * to ensure that no less than WalWriterDelay ms has passed between
+ * XLogBackgroundFlush calls - WaitLatch() might have returned
+ * instantaneously.
+ */
+ if (res & (WL_TIMEOUT | WL_POSTMASTER_DEATH))
+ return false;
+
+ /* WL_LATCH_SET is documented as reliable */
+ latch_set = (res & WL_LATCH_SET) != 0;
+ }
+
+ /*
+ * Nap for the configured time.
+ *
+ * On some platforms, signals won't interrupt the sleep. To ensure we
+ * respond reasonably promptly when someone signals us, break down the
+ * sleep into 1-second increments, and check for interrupts after each
+ * nap.
+ */
+ 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);
+
+ return latch_set;
+ }
/* --------------------------------
* signal handler routines
*************** wal_quickdie(SIGNAL_ARGS)
*** 298,311 ****
static void
WalSigHupHandler(SIGNAL_ARGS)
{
got_SIGHUP = true;
! SetLatch(WALWriterLatch());
}
/* SIGTERM: set flag to exit normally */
static void
WalShutdownHandler(SIGNAL_ARGS)
{
shutdown_requested = true;
! SetLatch(WALWriterLatch());
}
--- 431,465 ----
static void
WalSigHupHandler(SIGNAL_ARGS)
{
+ int save_errno = errno;
+
got_SIGHUP = true;
! if (MyProc)
! SetLatch(&MyProc->procLatch);
!
! errno = save_errno;
}
/* SIGTERM: set flag to exit normally */
static void
WalShutdownHandler(SIGNAL_ARGS)
{
+ int save_errno = errno;
+
shutdown_requested = true;
! if (MyProc)
! SetLatch(&MyProc->procLatch);
!
! errno = save_errno;
! }
!
! /* SIGUSR1: used for latch wakeups */
! static void
! walwriter_sigusr1_handler(SIGNAL_ARGS)
! {
! int save_errno = errno;
!
! latch_sigusr1_handler();
!
! errno = save_errno;
}
diff src/backend/storage/lmgr/proc.c
index d1bf264..43c4846
*** a/src/backend/storage/lmgr/proc.c
--- b/src/backend/storage/lmgr/proc.c
*************** InitProcGlobal(void)
*** 187,192 ****
--- 187,193 ----
ProcGlobal->startupProcPid = 0;
ProcGlobal->startupBufferPinWaitBufId = -1;
ProcGlobal->bgwriterLatch = NULL;
+ ProcGlobal->walwriterLatch = NULL;
/*
* Create and initialize all the PGPROC structures we'll need (except for
diff src/include/access/xlog.h
index f8aecef..3c1a509
*** a/src/include/access/xlog.h
--- b/src/include/access/xlog.h
*************** extern CheckpointStatsData CheckpointSta
*** 266,272 ****
extern XLogRecPtr XLogInsert(RmgrId rmid, uint8 info, XLogRecData *rdata);
extern void XLogFlush(XLogRecPtr RecPtr);
! extern void XLogBackgroundFlush(void);
extern bool XLogNeedsFlush(XLogRecPtr RecPtr);
extern int XLogFileInit(uint32 log, uint32 seg,
bool *use_existent, bool use_lock);
--- 266,272 ----
extern XLogRecPtr XLogInsert(RmgrId rmid, uint8 info, XLogRecData *rdata);
extern void XLogFlush(XLogRecPtr RecPtr);
! extern bool XLogBackgroundFlush(void);
extern bool XLogNeedsFlush(XLogRecPtr RecPtr);
extern int XLogFileInit(uint32 log, uint32 seg,
bool *use_existent, bool use_lock);
*************** extern TimeLineID GetRecoveryTargetTLI(v
*** 317,323 ****
extern bool CheckPromoteSignal(void);
extern void WakeupRecovery(void);
- extern Latch *WALWriterLatch(void);
/*
* Starting/stopping a base backup
--- 317,322 ----
diff src/include/storage/latch.h
index f97fedf..12f500a
*** a/src/include/storage/latch.h
--- b/src/include/storage/latch.h
***************
*** 25,31 ****
* and must be initialized at postmaster startup by InitSharedLatch. Before
* a shared latch can be waited on, it must be associated with a process
* with OwnLatch. Only the process owning the latch can wait on it, but any
! * process can set it.
*
* There are three basic operations on a latch:
*
--- 25,37 ----
* and must be initialized at postmaster startup by InitSharedLatch. Before
* a shared latch can be waited on, it must be associated with a process
* with OwnLatch. Only the process owning the latch can wait on it, but any
! * process can set it. Note that the use of the process latch (a field in
! * PGPROC) is generally preferred over an ad-hoc latch for auxiliary processes.
! * This is because generic signal handlers will call SetLatch on the process
! * latch only. Signals have the potential to invalidate the latch timeout on
! * certain platforms, resulting in a denial-of-service, so even if the process
! * latch cannot be used it is important to verify that all signal handlers
! * within the process call SetLatch().
*
* There are three basic operations on a latch:
*
diff src/include/storage/proc.h
index a66c484..478577f
*** a/src/include/storage/proc.h
--- b/src/include/storage/proc.h
*************** typedef struct PROC_HDR
*** 190,195 ****
--- 190,197 ----
PGPROC *autovacFreeProcs;
/* BGWriter process latch */
Latch *bgwriterLatch;
+ /* WALWriter process latch */
+ Latch *walwriterLatch;
/* Current shared estimate of appropriate spins_per_delay value */
int spins_per_delay;
/* The proc of the Startup process, since not in ProcArray */