mirror of
https://github.com/postgres/postgres.git
synced 2025-07-14 08:21:07 +03:00
Create a new dedicated Postgres process, "wal writer", which exists to write
and fsync WAL at convenient intervals. For the moment it just tries to offload this work from backends, but soon it will be responsible for guaranteeing a maximum delay before asynchronously-committed transactions will be flushed to disk. This is a portion of Simon Riggs' async-commit patch, committed to CVS separately because a background WAL writer seems like it might be a good idea independently of the async-commit feature. I rebased walwriter.c on bgwriter.c because it seemed like a more appropriate way of handling signals; while the startup/shutdown logic in postmaster.c is more like autovac because we want walwriter to quit before we start the shutdown checkpoint.
This commit is contained in:
@ -37,7 +37,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.534 2007/07/23 10:16:54 mha Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.535 2007/07/24 04:54:09 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
*
|
||||
@ -136,7 +136,7 @@ typedef struct bkend
|
||||
{
|
||||
pid_t pid; /* process id of backend */
|
||||
long cancel_key; /* cancel key for cancels for this backend */
|
||||
bool is_autovacuum; /* is it an autovacuum process */
|
||||
bool is_autovacuum; /* is it an autovacuum process? */
|
||||
} Backend;
|
||||
|
||||
static Dllist *BackendList;
|
||||
@ -144,9 +144,9 @@ static Dllist *BackendList;
|
||||
#ifdef EXEC_BACKEND
|
||||
/*
|
||||
* Number of entries in the backend table. Twice the number of backends,
|
||||
* plus four other subprocesses (stats, bgwriter, autovac, logger).
|
||||
* plus five other subprocesses (stats, bgwriter, walwriter, autovac, logger).
|
||||
*/
|
||||
#define NUM_BACKENDARRAY_ELEMS (2*MaxBackends + 4)
|
||||
#define NUM_BACKENDARRAY_ELEMS (2*MaxBackends + 5)
|
||||
static Backend *ShmemBackendArray;
|
||||
#endif
|
||||
|
||||
@ -201,6 +201,7 @@ char *bonjour_name;
|
||||
/* PIDs of special child processes; 0 when not running */
|
||||
static pid_t StartupPID = 0,
|
||||
BgWriterPID = 0,
|
||||
WalWriterPID = 0,
|
||||
AutoVacPID = 0,
|
||||
PgArchPID = 0,
|
||||
PgStatPID = 0,
|
||||
@ -221,7 +222,7 @@ bool ClientAuthInProgress = false; /* T during new-client
|
||||
bool redirection_done = false;
|
||||
|
||||
/* received START_AUTOVAC_LAUNCHER signal */
|
||||
static bool start_autovac_launcher = false;
|
||||
static volatile sig_atomic_t start_autovac_launcher = false;
|
||||
|
||||
/*
|
||||
* State for assigning random salts and cancel keys.
|
||||
@ -365,6 +366,7 @@ static void ShmemBackendArrayRemove(pid_t pid);
|
||||
|
||||
#define StartupDataBase() StartChildProcess(StartupProcess)
|
||||
#define StartBackgroundWriter() StartChildProcess(BgWriterProcess)
|
||||
#define StartWalWriter() StartChildProcess(WalWriterProcess)
|
||||
|
||||
/* Macros to check exit status of a child process */
|
||||
#define EXIT_STATUS_0(st) ((st) == 0)
|
||||
@ -909,8 +911,9 @@ PostmasterMain(int argc, char *argv[])
|
||||
*
|
||||
* CAUTION: when changing this list, check for side-effects on the signal
|
||||
* handling setup of child processes. See tcop/postgres.c,
|
||||
* bootstrap/bootstrap.c, postmaster/bgwriter.c, postmaster/autovacuum.c,
|
||||
* postmaster/pgarch.c, postmaster/pgstat.c, and postmaster/syslogger.c.
|
||||
* bootstrap/bootstrap.c, postmaster/bgwriter.c, postmaster/walwriter.c,
|
||||
* postmaster/autovacuum.c, postmaster/pgarch.c, postmaster/pgstat.c, and
|
||||
* postmaster/syslogger.c.
|
||||
*/
|
||||
pqinitmask();
|
||||
PG_SETMASK(&BlockSig);
|
||||
@ -1244,6 +1247,15 @@ ServerLoop(void)
|
||||
signal_child(BgWriterPID, SIGUSR2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Likewise, if we have lost the walwriter process, try to start a
|
||||
* new one. We don't need walwriter to complete a shutdown, so
|
||||
* don't start it if shutdown already initiated.
|
||||
*/
|
||||
if (WalWriterPID == 0 &&
|
||||
StartupPID == 0 && !FatalError && Shutdown == NoShutdown)
|
||||
WalWriterPID = StartWalWriter();
|
||||
|
||||
/* If we have lost the autovacuum launcher, try to start a new one */
|
||||
if (AutoVacPID == 0 &&
|
||||
(AutoVacuumingActive() || start_autovac_launcher) &&
|
||||
@ -1251,7 +1263,7 @@ ServerLoop(void)
|
||||
{
|
||||
AutoVacPID = StartAutoVacLauncher();
|
||||
if (AutoVacPID != 0)
|
||||
start_autovac_launcher = false; /* signal successfully processed */
|
||||
start_autovac_launcher = false; /* signal processed */
|
||||
}
|
||||
|
||||
/* If we have lost the archiver, try to start a new one */
|
||||
@ -1842,6 +1854,8 @@ SIGHUP_handler(SIGNAL_ARGS)
|
||||
SignalChildren(SIGHUP);
|
||||
if (BgWriterPID != 0)
|
||||
signal_child(BgWriterPID, SIGHUP);
|
||||
if (WalWriterPID != 0)
|
||||
signal_child(WalWriterPID, SIGHUP);
|
||||
if (AutoVacPID != 0)
|
||||
signal_child(AutoVacPID, SIGHUP);
|
||||
if (PgArchPID != 0)
|
||||
@ -1901,8 +1915,11 @@ pmdie(SIGNAL_ARGS)
|
||||
/* and the autovac launcher too */
|
||||
if (AutoVacPID != 0)
|
||||
signal_child(AutoVacPID, SIGTERM);
|
||||
/* and the walwriter too */
|
||||
if (WalWriterPID != 0)
|
||||
signal_child(WalWriterPID, SIGTERM);
|
||||
|
||||
if (DLGetHead(BackendList) || AutoVacPID != 0)
|
||||
if (DLGetHead(BackendList) || AutoVacPID != 0 || WalWriterPID != 0)
|
||||
break; /* let reaper() handle this */
|
||||
|
||||
/*
|
||||
@ -1938,7 +1955,7 @@ pmdie(SIGNAL_ARGS)
|
||||
ereport(LOG,
|
||||
(errmsg("received fast shutdown request")));
|
||||
|
||||
if (DLGetHead(BackendList) || AutoVacPID != 0)
|
||||
if (DLGetHead(BackendList) || AutoVacPID != 0 || WalWriterPID != 0)
|
||||
{
|
||||
if (!FatalError)
|
||||
{
|
||||
@ -1947,6 +1964,8 @@ pmdie(SIGNAL_ARGS)
|
||||
SignalChildren(SIGTERM);
|
||||
if (AutoVacPID != 0)
|
||||
signal_child(AutoVacPID, SIGTERM);
|
||||
if (WalWriterPID != 0)
|
||||
signal_child(WalWriterPID, SIGTERM);
|
||||
/* reaper() does the rest */
|
||||
}
|
||||
break;
|
||||
@ -1957,6 +1976,7 @@ pmdie(SIGNAL_ARGS)
|
||||
*
|
||||
* Note: if we previously got SIGTERM then we may send SIGUSR2 to
|
||||
* the bgwriter a second time here. This should be harmless.
|
||||
* Ditto for the signals to the other special children.
|
||||
*/
|
||||
if (StartupPID != 0)
|
||||
{
|
||||
@ -1993,6 +2013,8 @@ pmdie(SIGNAL_ARGS)
|
||||
signal_child(StartupPID, SIGQUIT);
|
||||
if (BgWriterPID != 0)
|
||||
signal_child(BgWriterPID, SIGQUIT);
|
||||
if (WalWriterPID != 0)
|
||||
signal_child(WalWriterPID, SIGQUIT);
|
||||
if (AutoVacPID != 0)
|
||||
signal_child(AutoVacPID, SIGQUIT);
|
||||
if (PgArchPID != 0)
|
||||
@ -2091,13 +2113,14 @@ reaper(SIGNAL_ARGS)
|
||||
|
||||
/*
|
||||
* Go to shutdown mode if a shutdown request was pending.
|
||||
* Otherwise, try to start the archiver, stats collector and
|
||||
* autovacuum launcher.
|
||||
* Otherwise, try to start the other special children.
|
||||
*/
|
||||
if (Shutdown > NoShutdown && BgWriterPID != 0)
|
||||
signal_child(BgWriterPID, SIGUSR2);
|
||||
else if (Shutdown == NoShutdown)
|
||||
{
|
||||
if (WalWriterPID == 0)
|
||||
WalWriterPID = StartWalWriter();
|
||||
if (XLogArchivingActive() && PgArchPID == 0)
|
||||
PgArchPID = pgarch_start();
|
||||
if (PgStatPID == 0)
|
||||
@ -2121,7 +2144,8 @@ reaper(SIGNAL_ARGS)
|
||||
BgWriterPID = 0;
|
||||
if (EXIT_STATUS_0(exitstatus) &&
|
||||
Shutdown > NoShutdown && !FatalError &&
|
||||
!DLGetHead(BackendList) && AutoVacPID == 0)
|
||||
!DLGetHead(BackendList) &&
|
||||
WalWriterPID == 0 && AutoVacPID == 0)
|
||||
{
|
||||
/*
|
||||
* Normal postmaster exit is here: we've seen normal exit of
|
||||
@ -2150,7 +2174,8 @@ reaper(SIGNAL_ARGS)
|
||||
* required will happen on next postmaster start.
|
||||
*/
|
||||
if (Shutdown > NoShutdown &&
|
||||
!DLGetHead(BackendList) && AutoVacPID == 0)
|
||||
!DLGetHead(BackendList) &&
|
||||
WalWriterPID == 0 && AutoVacPID == 0)
|
||||
{
|
||||
ereport(LOG,
|
||||
(errmsg("abnormal database system shutdown")));
|
||||
@ -2161,6 +2186,20 @@ reaper(SIGNAL_ARGS)
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Was it the wal writer? Normal exit can be ignored; we'll
|
||||
* start a new one at the next iteration of the postmaster's main loop,
|
||||
* if necessary. Any other exit condition is treated as a crash.
|
||||
*/
|
||||
if (WalWriterPID != 0 && pid == WalWriterPID)
|
||||
{
|
||||
WalWriterPID = 0;
|
||||
if (!EXIT_STATUS_0(exitstatus))
|
||||
HandleChildCrash(pid, exitstatus,
|
||||
_("wal writer process"));
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Was it the autovacuum launcher? Normal exit can be ignored; we'll
|
||||
* start a new one at the next iteration of the postmaster's main loop,
|
||||
@ -2233,7 +2272,8 @@ reaper(SIGNAL_ARGS)
|
||||
* StartupDataBase. (We can ignore the archiver and stats processes
|
||||
* here since they are not connected to shmem.)
|
||||
*/
|
||||
if (DLGetHead(BackendList) || StartupPID != 0 || BgWriterPID != 0 ||
|
||||
if (DLGetHead(BackendList) || StartupPID != 0 ||
|
||||
BgWriterPID != 0 || WalWriterPID != 0 ||
|
||||
AutoVacPID != 0)
|
||||
goto reaper_done;
|
||||
ereport(LOG,
|
||||
@ -2249,7 +2289,8 @@ reaper(SIGNAL_ARGS)
|
||||
|
||||
if (Shutdown > NoShutdown)
|
||||
{
|
||||
if (DLGetHead(BackendList) || StartupPID != 0 || AutoVacPID != 0)
|
||||
if (DLGetHead(BackendList) || StartupPID != 0 || AutoVacPID != 0 ||
|
||||
WalWriterPID != 0)
|
||||
goto reaper_done;
|
||||
/* Start the bgwriter if not running */
|
||||
if (BgWriterPID == 0)
|
||||
@ -2315,7 +2356,8 @@ CleanupBackend(int pid,
|
||||
}
|
||||
|
||||
/*
|
||||
* HandleChildCrash -- cleanup after failed backend, bgwriter, or autovacuum.
|
||||
* HandleChildCrash -- cleanup after failed backend, bgwriter, walwriter,
|
||||
* or autovacuum.
|
||||
*
|
||||
* The objectives here are to clean up our local state about the child
|
||||
* process, and to signal all other remaining children to quickdie.
|
||||
@ -2390,6 +2432,18 @@ HandleChildCrash(int pid, int exitstatus, const char *procname)
|
||||
signal_child(BgWriterPID, (SendStop ? SIGSTOP : SIGQUIT));
|
||||
}
|
||||
|
||||
/* Take care of the walwriter too */
|
||||
if (pid == WalWriterPID)
|
||||
WalWriterPID = 0;
|
||||
else if (WalWriterPID != 0 && !FatalError)
|
||||
{
|
||||
ereport(DEBUG2,
|
||||
(errmsg_internal("sending %s to process %d",
|
||||
(SendStop ? "SIGSTOP" : "SIGQUIT"),
|
||||
(int) WalWriterPID)));
|
||||
signal_child(WalWriterPID, (SendStop ? SIGSTOP : SIGQUIT));
|
||||
}
|
||||
|
||||
/* Take care of the autovacuum launcher too */
|
||||
if (pid == AutoVacPID)
|
||||
AutoVacPID = 0;
|
||||
@ -3622,9 +3676,11 @@ sigusr1_handler(SIGNAL_ARGS)
|
||||
start_autovac_launcher = true;
|
||||
}
|
||||
|
||||
/* The autovacuum launcher wants us to start a worker process. */
|
||||
if (CheckPostmasterSignal(PMSIGNAL_START_AUTOVAC_WORKER))
|
||||
{
|
||||
/* The autovacuum launcher wants us to start a worker process. */
|
||||
StartAutovacuumWorker();
|
||||
}
|
||||
|
||||
PG_SETMASK(&UnBlockSig);
|
||||
|
||||
@ -3805,6 +3861,10 @@ StartChildProcess(AuxProcType type)
|
||||
ereport(LOG,
|
||||
(errmsg("could not fork background writer process: %m")));
|
||||
break;
|
||||
case WalWriterProcess:
|
||||
ereport(LOG,
|
||||
(errmsg("could not fork wal writer process: %m")));
|
||||
break;
|
||||
default:
|
||||
ereport(LOG,
|
||||
(errmsg("could not fork process: %m")));
|
||||
|
Reference in New Issue
Block a user