
walsender.h should depend on xlog.h, not vice versa. (Actually, the inclusion was circular until a couple hours ago, which was even sillier; but Bruce broke it in the expedient rather than logically correct direction.) Because of that poor decision, plus blind application of pgrminclude, we had a situation where half the system was depending on xlog.h to include such unrelated stuff as array.h and guc.h. Clean up the header inclusion, and manually revert a lot of what pgrminclude had done so things build again. This episode reinforces my feeling that pgrminclude should not be run without adult supervision. Inclusion changes in header files in particular need to be reviewed with great care. More generally, it'd be good if we had a clearer notion of module layering to dictate which headers can sanely include which others ... but that's a big task for another day.
319 lines
9.0 KiB
C
319 lines
9.0 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* walwriter.c
|
|
*
|
|
* The WAL writer background process is new as of Postgres 8.3. It attempts
|
|
* to keep regular backends from having to write out (and fsync) WAL pages.
|
|
* Also, it guarantees that transaction commit records that weren't synced
|
|
* to disk immediately upon commit (ie, were "asynchronously committed")
|
|
* will reach disk within a knowable time --- which, as it happens, is at
|
|
* most three times the wal_writer_delay cycle time.
|
|
*
|
|
* 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.
|
|
*
|
|
* Because the walwriter's cycle is directly linked to the maximum delay
|
|
* before async-commit transactions are guaranteed committed, it's probably
|
|
* unwise to load additional functionality onto it. For instance, if you've
|
|
* got a yen to create xlog segments further in advance, that'd be better done
|
|
* in bgwriter than in walwriter.
|
|
*
|
|
* The walwriter is started by the postmaster as soon as the startup subprocess
|
|
* finishes. It remains alive until the postmaster commands it to terminate.
|
|
* Normal termination is by SIGTERM, which instructs the walwriter to exit(0).
|
|
* Emergency termination is by SIGQUIT; like any backend, the walwriter will
|
|
* simply abort and exit on SIGQUIT.
|
|
*
|
|
* If the walwriter exits unexpectedly, the postmaster treats that the same
|
|
* as a backend crash: shared memory may be corrupted, so remaining backends
|
|
* should be killed by SIGQUIT and then a recovery cycle started.
|
|
*
|
|
*
|
|
* Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
|
|
*
|
|
*
|
|
* IDENTIFICATION
|
|
* src/backend/postmaster/walwriter.c
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#include "postgres.h"
|
|
|
|
#include <signal.h>
|
|
#include <sys/time.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
#include "access/xlog.h"
|
|
#include "libpq/pqsignal.h"
|
|
#include "miscadmin.h"
|
|
#include "postmaster/walwriter.h"
|
|
#include "storage/bufmgr.h"
|
|
#include "storage/ipc.h"
|
|
#include "storage/lwlock.h"
|
|
#include "storage/pmsignal.h"
|
|
#include "storage/smgr.h"
|
|
#include "utils/guc.h"
|
|
#include "utils/hsearch.h"
|
|
#include "utils/memutils.h"
|
|
#include "utils/resowner.h"
|
|
|
|
|
|
/*
|
|
* GUC parameters
|
|
*/
|
|
int WalWriterDelay = 200;
|
|
|
|
/*
|
|
* 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;
|
|
|
|
/* Signal handlers */
|
|
static void wal_quickdie(SIGNAL_ARGS);
|
|
static void WalSigHupHandler(SIGNAL_ARGS);
|
|
static void WalShutdownHandler(SIGNAL_ARGS);
|
|
|
|
|
|
/*
|
|
* Main entry point for walwriter process
|
|
*
|
|
* This is invoked from BootstrapMain, which has already created the basic
|
|
* execution environment, but not enabled signals yet.
|
|
*/
|
|
void
|
|
WalWriterMain(void)
|
|
{
|
|
sigjmp_buf local_sigjmp_buf;
|
|
MemoryContext walwriter_context;
|
|
|
|
/*
|
|
* If possible, make this process a group leader, so that the postmaster
|
|
* can signal any child processes too. (walwriter probably never has any
|
|
* child processes, but for consistency we make all postmaster child
|
|
* processes do this.)
|
|
*/
|
|
#ifdef HAVE_SETSID
|
|
if (setsid() < 0)
|
|
elog(FATAL, "setsid() failed: %m");
|
|
#endif
|
|
|
|
/*
|
|
* Properly accept or ignore signals the postmaster might send us
|
|
*
|
|
* We have no particular use for SIGINT at the moment, but seems
|
|
* reasonable to treat like SIGTERM.
|
|
*/
|
|
pqsignal(SIGHUP, WalSigHupHandler); /* set flag to read config file */
|
|
pqsignal(SIGINT, WalShutdownHandler); /* request shutdown */
|
|
pqsignal(SIGTERM, WalShutdownHandler); /* request shutdown */
|
|
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 */
|
|
|
|
/*
|
|
* Reset some signals that are accepted by postmaster but not here
|
|
*/
|
|
pqsignal(SIGCHLD, SIG_DFL);
|
|
pqsignal(SIGTTIN, SIG_DFL);
|
|
pqsignal(SIGTTOU, SIG_DFL);
|
|
pqsignal(SIGCONT, SIG_DFL);
|
|
pqsignal(SIGWINCH, SIG_DFL);
|
|
|
|
/* We allow SIGQUIT (quickdie) at all times */
|
|
sigdelset(&BlockSig, SIGQUIT);
|
|
|
|
/*
|
|
* Create a resource owner to keep track of our resources (not clear that
|
|
* we need this, but may as well have one).
|
|
*/
|
|
CurrentResourceOwner = ResourceOwnerCreate(NULL, "Wal Writer");
|
|
|
|
/*
|
|
* Create a memory context that we will do all our work in. We do this so
|
|
* that we can reset the context during error recovery and thereby avoid
|
|
* possible memory leaks. Formerly this code just ran in
|
|
* TopMemoryContext, but resetting that would be a really bad idea.
|
|
*/
|
|
walwriter_context = AllocSetContextCreate(TopMemoryContext,
|
|
"Wal Writer",
|
|
ALLOCSET_DEFAULT_MINSIZE,
|
|
ALLOCSET_DEFAULT_INITSIZE,
|
|
ALLOCSET_DEFAULT_MAXSIZE);
|
|
MemoryContextSwitchTo(walwriter_context);
|
|
|
|
/*
|
|
* If an exception is encountered, processing resumes here.
|
|
*
|
|
* This code is heavily based on bgwriter.c, q.v.
|
|
*/
|
|
if (sigsetjmp(local_sigjmp_buf, 1) != 0)
|
|
{
|
|
/* Since not using PG_TRY, must reset error stack by hand */
|
|
error_context_stack = NULL;
|
|
|
|
/* Prevent interrupts while cleaning up */
|
|
HOLD_INTERRUPTS();
|
|
|
|
/* Report the error to the server log */
|
|
EmitErrorReport();
|
|
|
|
/*
|
|
* These operations are really just a minimal subset of
|
|
* AbortTransaction(). We don't have very many resources to worry
|
|
* about in walwriter, but we do have LWLocks, and perhaps buffers?
|
|
*/
|
|
LWLockReleaseAll();
|
|
AbortBufferIO();
|
|
UnlockBuffers();
|
|
/* buffer pins are released here: */
|
|
ResourceOwnerRelease(CurrentResourceOwner,
|
|
RESOURCE_RELEASE_BEFORE_LOCKS,
|
|
false, true);
|
|
/* we needn't bother with the other ResourceOwnerRelease phases */
|
|
AtEOXact_Buffers(false);
|
|
AtEOXact_Files();
|
|
AtEOXact_HashTables(false);
|
|
|
|
/*
|
|
* Now return to normal top-level context and clear ErrorContext for
|
|
* next time.
|
|
*/
|
|
MemoryContextSwitchTo(walwriter_context);
|
|
FlushErrorState();
|
|
|
|
/* Flush any leaked data in the top-level context */
|
|
MemoryContextResetAndDeleteChildren(walwriter_context);
|
|
|
|
/* Now we can allow interrupts again */
|
|
RESUME_INTERRUPTS();
|
|
|
|
/*
|
|
* Sleep at least 1 second after any error. A write error is likely
|
|
* to be repeated, and we don't want to be filling the error logs as
|
|
* fast as we can.
|
|
*/
|
|
pg_usleep(1000000L);
|
|
|
|
/*
|
|
* Close all open files after any error. This is helpful on Windows,
|
|
* where holding deleted files open causes various strange errors.
|
|
* It's not clear we need it elsewhere, but shouldn't hurt.
|
|
*/
|
|
smgrcloseall();
|
|
}
|
|
|
|
/* We can now handle ereport(ERROR) */
|
|
PG_exception_stack = &local_sigjmp_buf;
|
|
|
|
/*
|
|
* Unblock signals (they were blocked when the postmaster forked us)
|
|
*/
|
|
PG_SETMASK(&UnBlockSig);
|
|
|
|
/*
|
|
* Loop forever
|
|
*/
|
|
for (;;)
|
|
{
|
|
long udelay;
|
|
|
|
/*
|
|
* Emergency bailout if postmaster has died. This is to avoid the
|
|
* necessity for manual cleanup of all postmaster children.
|
|
*/
|
|
if (!PostmasterIsAlive())
|
|
exit(1);
|
|
|
|
/*
|
|
* Process any requests or signals received recently.
|
|
*/
|
|
if (got_SIGHUP)
|
|
{
|
|
got_SIGHUP = false;
|
|
ProcessConfigFile(PGC_SIGHUP);
|
|
}
|
|
if (shutdown_requested)
|
|
{
|
|
/* Normal exit from the walwriter is here */
|
|
proc_exit(0); /* done */
|
|
}
|
|
|
|
/*
|
|
* Do what we're here for...
|
|
*/
|
|
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);
|
|
}
|
|
}
|
|
|
|
|
|
/* --------------------------------
|
|
* signal handler routines
|
|
* --------------------------------
|
|
*/
|
|
|
|
/*
|
|
* wal_quickdie() occurs when signalled SIGQUIT by the postmaster.
|
|
*
|
|
* Some backend has bought the farm,
|
|
* so we need to stop what we're doing and exit.
|
|
*/
|
|
static void
|
|
wal_quickdie(SIGNAL_ARGS)
|
|
{
|
|
PG_SETMASK(&BlockSig);
|
|
|
|
/*
|
|
* We DO NOT want to run proc_exit() callbacks -- we're here because
|
|
* shared memory may be corrupted, so we don't want to try to clean up our
|
|
* transaction. Just nail the windows shut and get out of town. Now that
|
|
* there's an atexit callback to prevent third-party code from breaking
|
|
* things by calling exit() directly, we have to reset the callbacks
|
|
* explicitly to make this work as intended.
|
|
*/
|
|
on_exit_reset();
|
|
|
|
/*
|
|
* Note we do exit(2) not exit(0). This is to force the postmaster into a
|
|
* system reset cycle if some idiot DBA sends a manual SIGQUIT to a random
|
|
* backend. This is necessary precisely because we don't clean up our
|
|
* shared memory state. (The "dead man switch" mechanism in pmsignal.c
|
|
* should ensure the postmaster sees this as a crash, too, but no harm in
|
|
* being doubly sure.)
|
|
*/
|
|
exit(2);
|
|
}
|
|
|
|
/* SIGHUP: set flag to re-read config file at next convenient time */
|
|
static void
|
|
WalSigHupHandler(SIGNAL_ARGS)
|
|
{
|
|
got_SIGHUP = true;
|
|
}
|
|
|
|
/* SIGTERM: set flag to exit normally */
|
|
static void
|
|
WalShutdownHandler(SIGNAL_ARGS)
|
|
{
|
|
shutdown_requested = true;
|
|
}
|