Commit 5461564a authored by Tom Lane's avatar Tom Lane

Reduce idle power consumption of walwriter and checkpointer processes.

This patch modifies the walwriter process so that, when it has not found
anything useful to do for many consecutive wakeup cycles, it extends its
sleep time to reduce the server's idle power consumption.  It reverts to
normal as soon as it's done any successful flushes.  It's still true that
during any async commit, backends check for completed, unflushed pages of
WAL and signal the walwriter if there are any; so that in practice the
walwriter can get awakened and returned to normal operation sooner than the
sleep time might suggest.

Also, improve the checkpointer so that it uses a latch and a computed delay
time to not wake up at all except when it has something to do, replacing a
previous hardcoded 0.5 sec wakeup cycle.  This also is primarily useful for
reducing the server's power consumption when idle.

In passing, get rid of the dedicated latch for signaling the walwriter in
favor of using its procLatch, since that comports better with possible
generic signal handlers using that latch.  Also, fix a pre-existing bug
with failure to save/restore errno in walwriter's signal handlers.

Peter Geoghegan, somewhat simplified by Tom
parent 081ca7a0
...@@ -433,11 +433,6 @@ typedef struct XLogCtlData ...@@ -433,11 +433,6 @@ typedef struct XLogCtlData
*/ */
Latch recoveryWakeupLatch; 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. * During recovery, we keep a copy of the latest checkpoint record here.
* Used by the background writer when it wants to create a restartpoint. * Used by the background writer when it wants to create a restartpoint.
...@@ -1935,7 +1930,8 @@ XLogSetAsyncXactLSN(XLogRecPtr asyncXactLSN) ...@@ -1935,7 +1930,8 @@ XLogSetAsyncXactLSN(XLogRecPtr asyncXactLSN)
/* /*
* Nudge the WALWriter if we have a full page of WAL to write. * Nudge the WALWriter if we have a full page of WAL to write.
*/ */
SetLatch(&XLogCtl->WALWriterLatch); if (ProcGlobal->walwriterLatch)
SetLatch(ProcGlobal->walwriterLatch);
} }
/* /*
...@@ -2167,22 +2163,25 @@ XLogFlush(XLogRecPtr record) ...@@ -2167,22 +2163,25 @@ XLogFlush(XLogRecPtr record)
* block, and flush through the latest one of those. Thus, if async commits * block, and flush through the latest one of those. Thus, if async commits
* are not being used, we will flush complete blocks only. We can guarantee * are not being used, we will flush complete blocks only. We can guarantee
* that async commits reach disk after at most three cycles; normally only * that async commits reach disk after at most three cycles; normally only
* one or two. (We allow XLogWrite to write "flexibly", meaning it can stop * one or two. (When flushing complete blocks, we allow XLogWrite to write
* at the end of the buffer ring; this makes a difference only with very high * "flexibly", meaning it can stop at the end of the buffer ring; this makes a
* load or long wal_writer_delay, but imposes one extra cycle for the worst * difference only with very high load or long wal_writer_delay, but imposes
* case for async commits.) * one extra cycle for the worst case for async commits.)
* *
* This routine is invoked periodically by the background walwriter process. * This routine is invoked periodically by the background walwriter process.
*
* Returns TRUE if we flushed anything.
*/ */
void bool
XLogBackgroundFlush(void) XLogBackgroundFlush(void)
{ {
XLogRecPtr WriteRqstPtr; XLogRecPtr WriteRqstPtr;
bool flexible = true; bool flexible = true;
bool wrote_something = false;
/* XLOG doesn't need flushing during recovery */ /* XLOG doesn't need flushing during recovery */
if (RecoveryInProgress()) if (RecoveryInProgress())
return; return false;
/* read LogwrtResult and update local state */ /* read LogwrtResult and update local state */
{ {
...@@ -2224,7 +2223,7 @@ XLogBackgroundFlush(void) ...@@ -2224,7 +2223,7 @@ XLogBackgroundFlush(void)
XLogFileClose(); XLogFileClose();
} }
} }
return; return false;
} }
#ifdef WAL_DEBUG #ifdef WAL_DEBUG
...@@ -2247,10 +2246,13 @@ XLogBackgroundFlush(void) ...@@ -2247,10 +2246,13 @@ XLogBackgroundFlush(void)
WriteRqst.Write = WriteRqstPtr; WriteRqst.Write = WriteRqstPtr;
WriteRqst.Flush = WriteRqstPtr; WriteRqst.Flush = WriteRqstPtr;
XLogWrite(WriteRqst, flexible, false); XLogWrite(WriteRqst, flexible, false);
wrote_something = true;
} }
LWLockRelease(WALWriteLock); LWLockRelease(WALWriteLock);
END_CRIT_SECTION(); END_CRIT_SECTION();
return wrote_something;
} }
/* /*
...@@ -5101,7 +5103,6 @@ XLOGShmemInit(void) ...@@ -5101,7 +5103,6 @@ XLOGShmemInit(void)
XLogCtl->Insert.currpage = (XLogPageHeader) (XLogCtl->pages); XLogCtl->Insert.currpage = (XLogPageHeader) (XLogCtl->pages);
SpinLockInit(&XLogCtl->info_lck); SpinLockInit(&XLogCtl->info_lck);
InitSharedLatch(&XLogCtl->recoveryWakeupLatch); InitSharedLatch(&XLogCtl->recoveryWakeupLatch);
InitSharedLatch(&XLogCtl->WALWriterLatch);
/* /*
* If we are not in bootstrap mode, pg_control should already exist. Read * If we are not in bootstrap mode, pg_control should already exist. Read
...@@ -10478,12 +10479,3 @@ WakeupRecovery(void) ...@@ -10478,12 +10479,3 @@ WakeupRecovery(void)
{ {
SetLatch(&XLogCtl->recoveryWakeupLatch); SetLatch(&XLogCtl->recoveryWakeupLatch);
} }
/*
* Manage the WALWriterLatch
*/
Latch *
WALWriterLatch(void)
{
return &XLogCtl->WALWriterLatch;
}
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
#include "storage/ipc.h" #include "storage/ipc.h"
#include "storage/lwlock.h" #include "storage/lwlock.h"
#include "storage/pmsignal.h" #include "storage/pmsignal.h"
#include "storage/proc.h"
#include "storage/shmem.h" #include "storage/shmem.h"
#include "storage/smgr.h" #include "storage/smgr.h"
#include "storage/spin.h" #include "storage/spin.h"
...@@ -178,6 +179,7 @@ static void UpdateSharedMemoryConfig(void); ...@@ -178,6 +179,7 @@ static void UpdateSharedMemoryConfig(void);
static void chkpt_quickdie(SIGNAL_ARGS); static void chkpt_quickdie(SIGNAL_ARGS);
static void ChkptSigHupHandler(SIGNAL_ARGS); static void ChkptSigHupHandler(SIGNAL_ARGS);
static void ReqCheckpointHandler(SIGNAL_ARGS); static void ReqCheckpointHandler(SIGNAL_ARGS);
static void chkpt_sigusr1_handler(SIGNAL_ARGS);
static void ReqShutdownHandler(SIGNAL_ARGS); static void ReqShutdownHandler(SIGNAL_ARGS);
...@@ -224,7 +226,7 @@ CheckpointerMain(void) ...@@ -224,7 +226,7 @@ CheckpointerMain(void)
pqsignal(SIGQUIT, chkpt_quickdie); /* hard crash time */ pqsignal(SIGQUIT, chkpt_quickdie); /* hard crash time */
pqsignal(SIGALRM, SIG_IGN); pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN); pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, SIG_IGN); /* reserve for ProcSignal */ pqsignal(SIGUSR1, chkpt_sigusr1_handler);
pqsignal(SIGUSR2, ReqShutdownHandler); /* request shutdown */ pqsignal(SIGUSR2, ReqShutdownHandler); /* request shutdown */
/* /*
...@@ -359,6 +361,12 @@ CheckpointerMain(void) ...@@ -359,6 +361,12 @@ CheckpointerMain(void)
*/ */
UpdateSharedMemoryConfig(); UpdateSharedMemoryConfig();
/*
* Advertise our latch that backends can use to wake us up while we're
* sleeping.
*/
ProcGlobal->checkpointerLatch = &MyProc->procLatch;
/* /*
* Loop forever * Loop forever
*/ */
...@@ -368,6 +376,10 @@ CheckpointerMain(void) ...@@ -368,6 +376,10 @@ CheckpointerMain(void)
int flags = 0; int flags = 0;
pg_time_t now; pg_time_t now;
int elapsed_secs; int elapsed_secs;
int cur_timeout;
/* Clear any already-pending wakeups */
ResetLatch(&MyProc->procLatch);
/* /*
* Emergency bailout if postmaster has died. This is to avoid the * Emergency bailout if postmaster has died. This is to avoid the
...@@ -387,15 +399,15 @@ CheckpointerMain(void) ...@@ -387,15 +399,15 @@ CheckpointerMain(void)
ProcessConfigFile(PGC_SIGHUP); ProcessConfigFile(PGC_SIGHUP);
/* /*
* Checkpointer is the last process to shutdown, so we ask * Checkpointer is the last process to shut down, so we ask
* it to hold the keys for a range of other tasks required * it to hold the keys for a range of other tasks required
* most of which have nothing to do with checkpointing at all. * most of which have nothing to do with checkpointing at all.
* *
* For various reasons, some config values can change * For various reasons, some config values can change dynamically
* dynamically so are the primary copy of them is held in * so the primary copy of them is held in shared memory to make
* shared memory to make sure all backends see the same value. * sure all backends see the same value. We make Checkpointer
* We make Checkpointer responsible for updating the shared * responsible for updating the shared memory copy if the
* memory copy if the parameter setting changes because of SIGHUP. * parameter setting changes because of SIGHUP.
*/ */
UpdateSharedMemoryConfig(); UpdateSharedMemoryConfig();
} }
...@@ -488,7 +500,7 @@ CheckpointerMain(void) ...@@ -488,7 +500,7 @@ CheckpointerMain(void)
errhint("Consider increasing the configuration parameter \"checkpoint_segments\"."))); errhint("Consider increasing the configuration parameter \"checkpoint_segments\".")));
/* /*
* Initialize checkpointer-private variables used during checkpoint. * Initialize checkpointer-private variables used during checkpoint
*/ */
ckpt_active = true; ckpt_active = true;
if (!do_restartpoint) if (!do_restartpoint)
...@@ -543,20 +555,34 @@ CheckpointerMain(void) ...@@ -543,20 +555,34 @@ CheckpointerMain(void)
ckpt_active = false; ckpt_active = false;
} }
/* Check for archive_timeout and switch xlog files if necessary. */
CheckArchiveTimeout();
/* /*
* Send off activity statistics to the stats collector * Send off activity statistics to the stats collector
*/ */
pgstat_send_bgwriter(); pgstat_send_bgwriter();
/* /*
* Nap for a while and then loop again. Later patches will replace * Sleep until we are signaled or it's time for another checkpoint
* this with a latch loop. Keep it simple now for clarity. * or xlog file switch.
* Relatively long sleep because the bgwriter does cleanup now.
*/ */
pg_usleep(500000L); now = (pg_time_t) time(NULL);
elapsed_secs = now - last_checkpoint_time;
if (elapsed_secs >= CheckPointTimeout)
continue; /* no sleep for us ... */
cur_timeout = CheckPointTimeout - elapsed_secs;
if (XLogArchiveTimeout > 0 && !RecoveryInProgress())
{
elapsed_secs = now - last_xlog_switch_time;
if (elapsed_secs >= XLogArchiveTimeout)
continue; /* no sleep for us ... */
cur_timeout = Min(cur_timeout, XLogArchiveTimeout - elapsed_secs);
}
/* Check for archive_timeout and switch xlog files if necessary. */ (void) WaitLatch(&MyProc->procLatch,
CheckArchiveTimeout(); WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
cur_timeout * 1000L /* convert to ms */);
} }
} }
...@@ -814,21 +840,50 @@ chkpt_quickdie(SIGNAL_ARGS) ...@@ -814,21 +840,50 @@ chkpt_quickdie(SIGNAL_ARGS)
static void static void
ChkptSigHupHandler(SIGNAL_ARGS) ChkptSigHupHandler(SIGNAL_ARGS)
{ {
int save_errno = errno;
got_SIGHUP = true; got_SIGHUP = true;
if (MyProc)
SetLatch(&MyProc->procLatch);
errno = save_errno;
} }
/* SIGINT: set flag to run a normal checkpoint right away */ /* SIGINT: set flag to run a normal checkpoint right away */
static void static void
ReqCheckpointHandler(SIGNAL_ARGS) ReqCheckpointHandler(SIGNAL_ARGS)
{ {
int save_errno = errno;
checkpoint_requested = true; checkpoint_requested = true;
if (MyProc)
SetLatch(&MyProc->procLatch);
errno = save_errno;
}
/* SIGUSR1: used for latch wakeups */
static void
chkpt_sigusr1_handler(SIGNAL_ARGS)
{
int save_errno = errno;
latch_sigusr1_handler();
errno = save_errno;
} }
/* SIGUSR2: set flag to run a shutdown checkpoint and exit */ /* SIGUSR2: set flag to run a shutdown checkpoint and exit */
static void static void
ReqShutdownHandler(SIGNAL_ARGS) ReqShutdownHandler(SIGNAL_ARGS)
{ {
int save_errno = errno;
shutdown_requested = true; shutdown_requested = true;
if (MyProc)
SetLatch(&MyProc->procLatch);
errno = save_errno;
} }
...@@ -1055,6 +1110,7 @@ ForwardFsyncRequest(RelFileNodeBackend rnode, ForkNumber forknum, ...@@ -1055,6 +1110,7 @@ ForwardFsyncRequest(RelFileNodeBackend rnode, ForkNumber forknum,
BlockNumber segno) BlockNumber segno)
{ {
BgWriterRequest *request; BgWriterRequest *request;
bool too_full;
if (!IsUnderPostmaster) if (!IsUnderPostmaster)
return false; /* probably shouldn't even get here */ return false; /* probably shouldn't even get here */
...@@ -1068,14 +1124,13 @@ ForwardFsyncRequest(RelFileNodeBackend rnode, ForkNumber forknum, ...@@ -1068,14 +1124,13 @@ ForwardFsyncRequest(RelFileNodeBackend rnode, ForkNumber forknum,
BgWriterShmem->num_backend_writes++; BgWriterShmem->num_backend_writes++;
/* /*
* If the background writer isn't running or the request queue is full, * If the checkpointer isn't running or the request queue is full,
* the backend will have to perform its own fsync request. But before * the backend will have to perform its own fsync request. But before
* forcing that to happen, we can try to compact the background writer * forcing that to happen, we can try to compact the request queue.
* request queue.
*/ */
if (BgWriterShmem->checkpointer_pid == 0 || if (BgWriterShmem->checkpointer_pid == 0 ||
(BgWriterShmem->num_requests >= BgWriterShmem->max_requests (BgWriterShmem->num_requests >= BgWriterShmem->max_requests &&
&& !CompactCheckpointerRequestQueue())) !CompactCheckpointerRequestQueue()))
{ {
/* /*
* Count the subset of writes where backends have to do their own * Count the subset of writes where backends have to do their own
...@@ -1085,11 +1140,23 @@ ForwardFsyncRequest(RelFileNodeBackend rnode, ForkNumber forknum, ...@@ -1085,11 +1140,23 @@ ForwardFsyncRequest(RelFileNodeBackend rnode, ForkNumber forknum,
LWLockRelease(BgWriterCommLock); LWLockRelease(BgWriterCommLock);
return false; return false;
} }
/* OK, insert request */
request = &BgWriterShmem->requests[BgWriterShmem->num_requests++]; request = &BgWriterShmem->requests[BgWriterShmem->num_requests++];
request->rnode = rnode; request->rnode = rnode;
request->forknum = forknum; request->forknum = forknum;
request->segno = segno; request->segno = segno;
/* If queue is more than half full, nudge the checkpointer to empty it */
too_full = (BgWriterShmem->num_requests >=
BgWriterShmem->max_requests / 2);
LWLockRelease(BgWriterCommLock); LWLockRelease(BgWriterCommLock);
/* ... but not till after we release the lock */
if (too_full && ProcGlobal->checkpointerLatch)
SetLatch(ProcGlobal->checkpointerLatch);
return true; return true;
} }
...@@ -1109,7 +1176,7 @@ ForwardFsyncRequest(RelFileNodeBackend rnode, ForkNumber forknum, ...@@ -1109,7 +1176,7 @@ ForwardFsyncRequest(RelFileNodeBackend rnode, ForkNumber forknum,
* practice: there's one queue entry per shared buffer. * practice: there's one queue entry per shared buffer.
*/ */
static bool static bool
CompactCheckpointerRequestQueue() CompactCheckpointerRequestQueue(void)
{ {
struct BgWriterSlotMapping struct BgWriterSlotMapping
{ {
...@@ -1230,7 +1297,7 @@ AbsorbFsyncRequests(void) ...@@ -1230,7 +1297,7 @@ AbsorbFsyncRequests(void)
*/ */
LWLockAcquire(BgWriterCommLock, LW_EXCLUSIVE); LWLockAcquire(BgWriterCommLock, LW_EXCLUSIVE);
/* Transfer write count into pending pgstats message */ /* Transfer stats counts into pending pgstats message */
BgWriterStats.m_buf_written_backend += BgWriterShmem->num_backend_writes; BgWriterStats.m_buf_written_backend += BgWriterShmem->num_backend_writes;
BgWriterStats.m_buf_fsync_backend += BgWriterShmem->num_backend_fsync; BgWriterStats.m_buf_fsync_backend += BgWriterShmem->num_backend_fsync;
......
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
#include "storage/ipc.h" #include "storage/ipc.h"
#include "storage/lwlock.h" #include "storage/lwlock.h"
#include "storage/pmsignal.h" #include "storage/pmsignal.h"
#include "storage/proc.h"
#include "storage/smgr.h" #include "storage/smgr.h"
#include "utils/guc.h" #include "utils/guc.h"
#include "utils/hsearch.h" #include "utils/hsearch.h"
...@@ -66,6 +67,14 @@ ...@@ -66,6 +67,14 @@
*/ */
int WalWriterDelay = 200; int WalWriterDelay = 200;
/*
* Number of do-nothing loops before lengthening the delay time, and the
* multiplier to apply to WalWriterDelay when we do decide to hibernate.
* (Perhaps these need to be configurable?)
*/
#define LOOPS_UNTIL_HIBERNATE 50
#define HIBERNATE_FACTOR 25
/* /*
* Flags set by interrupt handlers for later service in the main loop. * Flags set by interrupt handlers for later service in the main loop.
*/ */
...@@ -76,6 +85,7 @@ static volatile sig_atomic_t shutdown_requested = false; ...@@ -76,6 +85,7 @@ static volatile sig_atomic_t shutdown_requested = false;
static void wal_quickdie(SIGNAL_ARGS); static void wal_quickdie(SIGNAL_ARGS);
static void WalSigHupHandler(SIGNAL_ARGS); static void WalSigHupHandler(SIGNAL_ARGS);
static void WalShutdownHandler(SIGNAL_ARGS); static void WalShutdownHandler(SIGNAL_ARGS);
static void walwriter_sigusr1_handler(SIGNAL_ARGS);
/* /*
* Main entry point for walwriter process * Main entry point for walwriter process
...@@ -88,8 +98,7 @@ WalWriterMain(void) ...@@ -88,8 +98,7 @@ WalWriterMain(void)
{ {
sigjmp_buf local_sigjmp_buf; sigjmp_buf local_sigjmp_buf;
MemoryContext walwriter_context; MemoryContext walwriter_context;
int left_till_hibernate;
InitLatch(WALWriterLatch()); /* initialize latch used in main loop */
/* /*
* If possible, make this process a group leader, so that the postmaster * If possible, make this process a group leader, so that the postmaster
...@@ -114,7 +123,7 @@ WalWriterMain(void) ...@@ -114,7 +123,7 @@ WalWriterMain(void)
pqsignal(SIGQUIT, wal_quickdie); /* hard crash time */ pqsignal(SIGQUIT, wal_quickdie); /* hard crash time */
pqsignal(SIGALRM, SIG_IGN); pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN); pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, SIG_IGN); /* reserve for ProcSignal */ pqsignal(SIGUSR1, walwriter_sigusr1_handler);
pqsignal(SIGUSR2, SIG_IGN); /* not used */ pqsignal(SIGUSR2, SIG_IGN); /* not used */
/* /*
...@@ -217,12 +226,26 @@ WalWriterMain(void) ...@@ -217,12 +226,26 @@ WalWriterMain(void)
*/ */
PG_SETMASK(&UnBlockSig); PG_SETMASK(&UnBlockSig);
/*
* Reset hibernation state after any error.
*/
left_till_hibernate = LOOPS_UNTIL_HIBERNATE;
/*
* Advertise our latch that backends can use to wake us up while we're
* sleeping.
*/
ProcGlobal->walwriterLatch = &MyProc->procLatch;
/* /*
* Loop forever * Loop forever
*/ */
for (;;) for (;;)
{ {
ResetLatch(WALWriterLatch()); long cur_timeout;
/* Clear any already-pending wakeups */
ResetLatch(&MyProc->procLatch);
/* /*
* Emergency bailout if postmaster has died. This is to avoid the * Emergency bailout if postmaster has died. This is to avoid the
...@@ -246,13 +269,27 @@ WalWriterMain(void) ...@@ -246,13 +269,27 @@ WalWriterMain(void)
} }
/* /*
* Do what we're here for... * Do what we're here for; then, if XLogBackgroundFlush() found useful
* work to do, reset hibernation counter.
*/ */
XLogBackgroundFlush(); if (XLogBackgroundFlush())
left_till_hibernate = LOOPS_UNTIL_HIBERNATE;
else if (left_till_hibernate > 0)
left_till_hibernate--;
(void) WaitLatch(WALWriterLatch(), /*
WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, * Sleep until we are signaled or WalWriterDelay has elapsed. If we
WalWriterDelay /* ms */); * haven't done anything useful for quite some time, lengthen the
* sleep time so as to reduce the server's idle power consumption.
*/
if (left_till_hibernate > 0)
cur_timeout = WalWriterDelay; /* in ms */
else
cur_timeout = WalWriterDelay * HIBERNATE_FACTOR;
(void) WaitLatch(&MyProc->procLatch,
WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
cur_timeout);
} }
} }
...@@ -298,14 +335,35 @@ wal_quickdie(SIGNAL_ARGS) ...@@ -298,14 +335,35 @@ wal_quickdie(SIGNAL_ARGS)
static void static void
WalSigHupHandler(SIGNAL_ARGS) WalSigHupHandler(SIGNAL_ARGS)
{ {
int save_errno = errno;
got_SIGHUP = true; got_SIGHUP = true;
SetLatch(WALWriterLatch()); if (MyProc)
SetLatch(&MyProc->procLatch);
errno = save_errno;
} }
/* SIGTERM: set flag to exit normally */ /* SIGTERM: set flag to exit normally */
static void static void
WalShutdownHandler(SIGNAL_ARGS) WalShutdownHandler(SIGNAL_ARGS)
{ {
int save_errno = errno;
shutdown_requested = true; shutdown_requested = true;
SetLatch(WALWriterLatch()); 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;
} }
...@@ -187,6 +187,8 @@ InitProcGlobal(void) ...@@ -187,6 +187,8 @@ InitProcGlobal(void)
ProcGlobal->startupProcPid = 0; ProcGlobal->startupProcPid = 0;
ProcGlobal->startupBufferPinWaitBufId = -1; ProcGlobal->startupBufferPinWaitBufId = -1;
ProcGlobal->bgwriterLatch = NULL; ProcGlobal->bgwriterLatch = NULL;
ProcGlobal->walwriterLatch = NULL;
ProcGlobal->checkpointerLatch = NULL;
/* /*
* Create and initialize all the PGPROC structures we'll need (except for * Create and initialize all the PGPROC structures we'll need (except for
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
#include "datatype/timestamp.h" #include "datatype/timestamp.h"
#include "lib/stringinfo.h" #include "lib/stringinfo.h"
#include "storage/buf.h" #include "storage/buf.h"
#include "storage/latch.h"
#include "utils/pg_crc.h" #include "utils/pg_crc.h"
/* /*
...@@ -266,7 +265,7 @@ extern CheckpointStatsData CheckpointStats; ...@@ -266,7 +265,7 @@ extern CheckpointStatsData CheckpointStats;
extern XLogRecPtr XLogInsert(RmgrId rmid, uint8 info, XLogRecData *rdata); extern XLogRecPtr XLogInsert(RmgrId rmid, uint8 info, XLogRecData *rdata);
extern void XLogFlush(XLogRecPtr RecPtr); extern void XLogFlush(XLogRecPtr RecPtr);
extern void XLogBackgroundFlush(void); extern bool XLogBackgroundFlush(void);
extern bool XLogNeedsFlush(XLogRecPtr RecPtr); extern bool XLogNeedsFlush(XLogRecPtr RecPtr);
extern int XLogFileInit(uint32 log, uint32 seg, extern int XLogFileInit(uint32 log, uint32 seg,
bool *use_existent, bool use_lock); bool *use_existent, bool use_lock);
...@@ -317,7 +316,6 @@ extern TimeLineID GetRecoveryTargetTLI(void); ...@@ -317,7 +316,6 @@ extern TimeLineID GetRecoveryTargetTLI(void);
extern bool CheckPromoteSignal(void); extern bool CheckPromoteSignal(void);
extern void WakeupRecovery(void); extern void WakeupRecovery(void);
extern Latch *WALWriterLatch(void);
/* /*
* Starting/stopping a base backup * Starting/stopping a base backup
......
...@@ -64,6 +64,15 @@ ...@@ -64,6 +64,15 @@
* will be lifted in future by inserting suitable memory barriers into * will be lifted in future by inserting suitable memory barriers into
* SetLatch and ResetLatch. * SetLatch and ResetLatch.
* *
* Note that use of the process latch (PGPROC.procLatch) is generally better
* than an ad-hoc shared latch for signaling auxiliary processes. This is
* because generic signal handlers will call SetLatch on the process latch
* only, so using any latch other than the process latch effectively precludes
* ever registering a generic handler. Since signals have the potential to
* invalidate the latch timeout on some platforms, resulting in a
* denial-of-service, it is important to verify that all signal handlers
* within all WaitLatch-calling processes call SetLatch.
*
* *
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
......
...@@ -188,8 +188,12 @@ typedef struct PROC_HDR ...@@ -188,8 +188,12 @@ typedef struct PROC_HDR
PGPROC *freeProcs; PGPROC *freeProcs;
/* Head of list of autovacuum's free PGPROC structures */ /* Head of list of autovacuum's free PGPROC structures */
PGPROC *autovacFreeProcs; PGPROC *autovacFreeProcs;
/* BGWriter process latch */ /* BGWriter process's latch */
Latch *bgwriterLatch; Latch *bgwriterLatch;
/* WALWriter process's latch */
Latch *walwriterLatch;
/* Checkpointer process's latch */
Latch *checkpointerLatch;
/* Current shared estimate of appropriate spins_per_delay value */ /* Current shared estimate of appropriate spins_per_delay value */
int spins_per_delay; int spins_per_delay;
/* The proc of the Startup process, since not in ProcArray */ /* The proc of the Startup process, since not in ProcArray */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment