5151#include "storage/ipc.h"
5252#include "storage/lwlock.h"
5353#include "storage/pmsignal.h"
54+ #include "storage/proc.h"
5455#include "storage/shmem.h"
5556#include "storage/smgr.h"
5657#include "storage/spin.h"
6465 */
6566int BgWriterDelay = 200 ;
6667
68+ /*
69+ * Time to sleep between bgwriter rounds, when it has no work to do.
70+ */
71+ #define BGWRITER_HIBERNATE_MS 10000
72+
6773/*
6874 * Flags set by interrupt handlers for later service in the main loop.
6975 */
@@ -77,13 +83,14 @@ static bool am_bg_writer = false;
7783
7884/* Prototypes for private functions */
7985
80- static void BgWriterNap (void );
86+ static void BgWriterNap (bool hibernating );
8187
8288/* Signal handlers */
8389
8490static void bg_quickdie (SIGNAL_ARGS );
8591static void BgSigHupHandler (SIGNAL_ARGS );
8692static void ReqShutdownHandler (SIGNAL_ARGS );
93+ static void bgwriter_sigusr1_handler (SIGNAL_ARGS );
8794
8895
8996/*
@@ -97,6 +104,7 @@ BackgroundWriterMain(void)
97104{
98105 sigjmp_buf local_sigjmp_buf ;
99106 MemoryContext bgwriter_context ;
107+ bool hibernating ;
100108
101109 am_bg_writer = true;
102110
@@ -112,18 +120,18 @@ BackgroundWriterMain(void)
112120#endif
113121
114122 /*
115- * Properly accept or ignore signals the postmaster might send us
123+ * Properly accept or ignore signals the postmaster might send us.
116124 *
117- * SIGUSR1 is presently unused; keep it spare in case someday we want this
118- * process to participate in ProcSignal signalling .
125+ * bgwriter doesn't participate in ProcSignal signalling, but a SIGUSR1
126+ * handler is still needed for latch wakeups .
119127 */
120128 pqsignal (SIGHUP , BgSigHupHandler ); /* set flag to read config file */
121129 pqsignal (SIGINT , SIG_IGN ); /* as of 9.2 no longer requests checkpoint */
122130 pqsignal (SIGTERM , ReqShutdownHandler ); /* shutdown */
123131 pqsignal (SIGQUIT , bg_quickdie ); /* hard crash time */
124132 pqsignal (SIGALRM , SIG_IGN );
125133 pqsignal (SIGPIPE , SIG_IGN );
126- pqsignal (SIGUSR1 , SIG_IGN ); /* reserve for ProcSignal */
134+ pqsignal (SIGUSR1 , bgwriter_sigusr1_handler );
127135 pqsignal (SIGUSR2 , SIG_IGN );
128136
129137 /*
@@ -138,6 +146,12 @@ BackgroundWriterMain(void)
138146 /* We allow SIGQUIT (quickdie) at all times */
139147 sigdelset (& BlockSig , SIGQUIT );
140148
149+ /*
150+ * Advertise our latch that backends can use to wake us up while we're
151+ * sleeping.
152+ */
153+ ProcGlobal -> bgwriterLatch = & MyProc -> procLatch ;
154+
141155 /*
142156 * Create a resource owner to keep track of our resources (currently only
143157 * buffer pins).
@@ -235,8 +249,11 @@ BackgroundWriterMain(void)
235249 /*
236250 * Loop forever
237251 */
252+ hibernating = false;
238253 for (;;)
239254 {
255+ bool lapped ;
256+
240257 /*
241258 * Emergency bailout if postmaster has died. This is to avoid the
242259 * necessity for manual cleanup of all postmaster children.
@@ -264,18 +281,66 @@ BackgroundWriterMain(void)
264281 /*
265282 * Do one cycle of dirty-buffer writing.
266283 */
267- BgBufferSync ();
284+ if (hibernating && bgwriter_lru_maxpages > 0 )
285+ ResetLatch (& MyProc -> procLatch );
286+ lapped = BgBufferSync ();
287+
288+ if (lapped && !hibernating )
289+ {
290+ /*
291+ * BgBufferSync did nothing. Since there doesn't seem to be any
292+ * work for the bgwriter to do, go into slower-paced
293+ * "hibernation" mode, where we sleep for much longer times than
294+ * bgwriter_delay says. Fewer wakeups saves electricity. If a
295+ * backend starts dirtying pages again, it will wake us up by
296+ * setting our latch.
297+ *
298+ * The latch is kept set during productive cycles where buffers
299+ * are written, and only reset before going into a longer sleep.
300+ * That ensures that when there's a constant trickle of activity,
301+ * the SetLatch() calls that backends have to do will see the
302+ * latch as already set, and are not slowed down by having to
303+ * actually set the latch and signal us.
304+ */
305+ hibernating = true;
268306
269- /* Nap for the configured time. */
270- BgWriterNap ();
307+ /*
308+ * Take one more short nap and perform one more bgwriter cycle -
309+ * someone might've dirtied a buffer just after we finished the
310+ * previous bgwriter cycle, while the latch was still set. If
311+ * we still find nothing to do after this cycle, the next sleep
312+ * will be longer.
313+ */
314+ BgWriterNap (false);
315+ continue ;
316+ }
317+ else if (!lapped && hibernating )
318+ {
319+ /*
320+ * Woken up from hibernation. Set the latch just in case it's
321+ * not set yet (usually we wake up from hibernation because a
322+ * backend already set the latch, but not necessarily).
323+ */
324+ SetLatch (& MyProc -> procLatch );
325+ hibernating = false;
326+ }
327+
328+ /*
329+ * Take a short or long nap, depending on whether there was any work
330+ * to do.
331+ */
332+ BgWriterNap (hibernating );
271333 }
272334}
273335
274336/*
275337 * BgWriterNap -- Nap for the configured time or until a signal is received.
338+ *
339+ * If 'hibernating' is false, sleeps for bgwriter_delay milliseconds.
340+ * Otherwise sleeps longer, but also wakes up if the process latch is set.
276341 */
277342static void
278- BgWriterNap (void )
343+ BgWriterNap (bool hibernating )
279344{
280345 long udelay ;
281346
@@ -285,18 +350,44 @@ BgWriterNap(void)
285350 pgstat_send_bgwriter ();
286351
287352 /*
288- * Nap for the configured time, or sleep for 10 seconds if there is no
289- * bgwriter activity configured.
353+ * If there was no work to do in the previous bgwriter cycle, take a
354+ * longer nap.
355+ */
356+ if (hibernating )
357+ {
358+ /*
359+ * We wake on a buffer being dirtied. It's possible that some
360+ * useful work will become available for the bgwriter to do without
361+ * a buffer actually being dirtied, like when a dirty buffer's usage
362+ * count is decremented to zero or it's unpinned. This corner case
363+ * is judged as too marginal to justify adding additional SetLatch()
364+ * calls in very hot code paths, cheap though those calls may be.
365+ *
366+ * We still wake up periodically, so that BufferAlloc stats are
367+ * updated reasonably promptly.
368+ */
369+ int res = WaitLatch (& MyProc -> procLatch ,
370+ WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH ,
371+ BGWRITER_HIBERNATE_MS );
372+
373+ /*
374+ * Only do a quick return if timeout was reached (or postmaster died)
375+ * to ensure that no less than BgWriterDelay ms has passed between
376+ * BgBufferSyncs - WaitLatch() might have returned instantaneously.
377+ */
378+ if (res & (WL_TIMEOUT | WL_POSTMASTER_DEATH ))
379+ return ;
380+ }
381+
382+ /*
383+ * Nap for the configured time.
290384 *
291385 * On some platforms, signals won't interrupt the sleep. To ensure we
292386 * respond reasonably promptly when someone signals us, break down the
293387 * sleep into 1-second increments, and check for interrupts after each
294388 * nap.
295389 */
296- if (bgwriter_lru_maxpages > 0 )
297- udelay = BgWriterDelay * 1000L ;
298- else
299- udelay = 10000000L ; /* Ten seconds */
390+ udelay = BgWriterDelay * 1000L ;
300391
301392 while (udelay > 999999L )
302393 {
@@ -351,12 +442,35 @@ bg_quickdie(SIGNAL_ARGS)
351442static void
352443BgSigHupHandler (SIGNAL_ARGS )
353444{
445+ int save_errno = errno ;
446+
354447 got_SIGHUP = true;
448+ if (MyProc )
449+ SetLatch (& MyProc -> procLatch );
450+
451+ errno = save_errno ;
355452}
356453
357454/* SIGTERM: set flag to shutdown and exit */
358455static void
359456ReqShutdownHandler (SIGNAL_ARGS )
360457{
458+ int save_errno = errno ;
459+
361460 shutdown_requested = true;
461+ if (MyProc )
462+ SetLatch (& MyProc -> procLatch );
463+
464+ errno = save_errno ;
465+ }
466+
467+ /* SIGUSR1: used for latch wakeups */
468+ static void
469+ bgwriter_sigusr1_handler (SIGNAL_ARGS )
470+ {
471+ int save_errno = errno ;
472+
473+ latch_sigusr1_handler ();
474+
475+ errno = save_errno ;
362476}
0 commit comments