* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/access/transam/slru.c,v 1.14 2004/05/28 05:12:42 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/slru.c,v 1.15 2004/05/29 22:48:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include <unistd.h>
#include "access/slru.h"
+#include "postmaster/bgwriter.h"
#include "storage/fd.h"
#include "storage/lwlock.h"
#include "miscadmin.h"
if (!SlruScanDirectory(ctl, cutoffPage, false))
return; /* nothing to remove */
- /* Perform a forced CHECKPOINT */
- CreateCheckPoint(false, true);
+ /* Perform a CHECKPOINT */
+ RequestCheckpoint(true);
/*
* Scan shared memory and remove any pages preceding the cutoff page,
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.144 2004/05/28 05:12:42 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.145 2004/05/29 22:48:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "access/xlogutils.h"
#include "catalog/catversion.h"
#include "catalog/pg_control.h"
+#include "postmaster/bgwriter.h"
#include "storage/bufpage.h"
#include "storage/fd.h"
#include "storage/lwlock.h"
-#include "storage/pmsignal.h"
#include "storage/proc.h"
#include "storage/sinval.h"
#include "storage/spin.h"
{
#ifdef WAL_DEBUG
if (XLOG_DEBUG)
- elog(LOG, "time for a checkpoint, signaling postmaster");
+ elog(LOG, "time for a checkpoint, signaling bgwriter");
#endif
- SendPostmasterSignal(PMSIGNAL_DO_CHECKPOINT);
+ RequestCheckpoint(false);
}
}
LWLockRelease(ControlFileLock);
RmgrTable[rmid].rm_cleanup();
}
- /* suppress in-transaction check in CreateCheckPoint */
- MyLastRecPtr.xrecoff = 0;
- MyXactMadeXLogEntry = false;
- MyXactMadeTempRelUpdate = false;
-
/*
* At this point, ThisStartUpID is the largest SUI that we could
* find evidence for in the WAL entries. But check it against
ereport(LOG,
(errmsg("shutting down")));
- /* suppress in-transaction check in CreateCheckPoint */
- MyLastRecPtr.xrecoff = 0;
- MyXactMadeXLogEntry = false;
- MyXactMadeTempRelUpdate = false;
-
CritSectionCount++;
CreateCheckPoint(true, true);
ShutdownCLOG();
uint32 _logId;
uint32 _logSeg;
- if (MyXactMadeXLogEntry)
- ereport(ERROR,
- (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
- errmsg("checkpoint cannot be made inside transaction block")));
-
/*
* Acquire CheckpointLock to ensure only one checkpoint happens at a
- * time.
- *
- * The CheckpointLock can be held for quite a while, which is not good
- * because we won't respond to a cancel/die request while waiting for
- * an LWLock. (But the alternative of using a regular lock won't work
- * for background checkpoint processes, which are not regular
- * backends.) So, rather than use a plain LWLockAcquire, use this
- * kluge to allow an interrupt to be accepted while we are waiting:
+ * time. (This is just pro forma, since in the present system
+ * structure there is only one process that is allowed to issue
+ * checkpoints at any given time.)
*/
- while (!LWLockConditionalAcquire(CheckpointLock, LW_EXCLUSIVE))
- {
- CHECK_FOR_INTERRUPTS();
- pg_usleep(1000000L);
- }
+ LWLockAcquire(CheckpointLock, LW_EXCLUSIVE);
/*
* Use a critical section to force system panic if we have trouble.
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.181 2004/05/28 05:12:45 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.182 2004/05/29 22:48:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "executor/executor.h"
#include "libpq/pqsignal.h"
#include "miscadmin.h"
+#include "postmaster/bgwriter.h"
#include "pgtime.h"
#include "storage/freespace.h"
#include "storage/ipc.h"
#define ALLOC(t, c) ((t *) calloc((unsigned)(c), sizeof(t)))
extern int Int_yyparse(void);
+static void usage(void);
+static void bootstrap_signals(void);
static hashnode *AddStr(char *str, int strlength, int mderef);
static Form_pg_attribute AllocateAttribute(void);
static bool BootstrapAlreadySeen(Oid id);
static IndexList *ILHead = NULL;
-/* ----------------------------------------------------------------
- * misc functions
- * ----------------------------------------------------------------
- */
-
-/* ----------------
- * error handling / abort routines
- * ----------------
- */
-void
-err_out(void)
-{
- Warnings++;
- cleanup();
-}
-
-/* usage:
- * usage help for the bootstrap backend
- */
-static void
-usage(void)
-{
- fprintf(stderr,
- gettext("Usage:\n"
- " postgres -boot [OPTION]... DBNAME\n"
- " -c NAME=VALUE set run-time parameter\n"
- " -d 1-5 debug level\n"
- " -D datadir data directory\n"
- " -F turn off fsync\n"
- " -o file send debug output to file\n"
- " -x num internal use\n"));
-
- proc_exit(1);
-}
-
-
/*
- * The main loop for running the backend in bootstrap mode
+ * The main entry point for running the backend in bootstrap mode
*
* The bootstrap mode is used to initialize the template database.
* The bootstrap backend doesn't speak SQL, but instead expects
switch (xlogop)
{
case BS_XLOG_STARTUP:
- statmsg = "startup subprocess";
- break;
- case BS_XLOG_CHECKPOINT:
- statmsg = "checkpoint subprocess";
+ statmsg = "startup process";
break;
case BS_XLOG_BGWRITER:
- statmsg = "bgwriter subprocess";
- break;
- case BS_XLOG_SHUTDOWN:
- statmsg = "shutdown subprocess";
+ statmsg = "writer process";
break;
default:
- statmsg = "??? subprocess";
+ statmsg = "??? process";
break;
}
init_ps_display(statmsg, "", "");
pg_timezone_initialize();
}
- if (IsUnderPostmaster)
- {
- /*
- * Properly accept or ignore signals the postmaster might send us
- */
- pqsignal(SIGHUP, SIG_IGN);
- pqsignal(SIGINT, SIG_IGN); /* ignore query-cancel */
- pqsignal(SIGTERM, die);
- pqsignal(SIGQUIT, quickdie);
- pqsignal(SIGALRM, SIG_IGN);
- pqsignal(SIGPIPE, SIG_IGN);
- pqsignal(SIGUSR1, SIG_IGN);
- pqsignal(SIGUSR2, SIG_IGN);
-
- /*
- * 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);
-
- /*
- * Unblock signals (they were blocked when the postmaster forked
- * us)
- */
- PG_SETMASK(&UnBlockSig);
- }
- else
- {
- /* Set up appropriately for interactive use */
- pqsignal(SIGHUP, die);
- pqsignal(SIGINT, die);
- pqsignal(SIGTERM, die);
- pqsignal(SIGQUIT, die);
-
- /*
- * Create lockfile for data directory.
- */
+ /* If standalone, create lockfile for data directory */
+ if (!IsUnderPostmaster)
CreateDataDirLockFile(DataDir, false);
- }
SetProcessingMode(BootstrapProcessing);
IgnoreSystemIndexes(true);
switch (xlogop)
{
case BS_XLOG_NOP:
+ bootstrap_signals();
break;
case BS_XLOG_BOOTSTRAP:
+ bootstrap_signals();
BootStrapXLOG();
StartupXLOG();
break;
- case BS_XLOG_CHECKPOINT:
- InitXLOGAccess();
- CreateCheckPoint(false, false);
- proc_exit(0); /* done */
-
- case BS_XLOG_BGWRITER:
- InitXLOGAccess();
- BufferBackgroundWriter();
- proc_exit(0); /* done */
-
case BS_XLOG_STARTUP:
+ bootstrap_signals();
StartupXLOG();
LoadFreeSpaceMap();
- proc_exit(0); /* done */
+ proc_exit(0); /* startup done */
- case BS_XLOG_SHUTDOWN:
+ case BS_XLOG_BGWRITER:
+ /* don't set signals, bgwriter has its own agenda */
InitXLOGAccess();
- ShutdownXLOG(0, 0);
- DumpFreeSpaceMap(0, 0);
- proc_exit(0); /* done */
+ BackgroundWriterMain();
+ proc_exit(1); /* should never return */
default:
elog(PANIC, "unrecognized XLOG op: %d", xlogop);
- proc_exit(0);
+ proc_exit(1);
}
SetProcessingMode(BootstrapProcessing);
/* not reached, here to make compiler happy */
return 0;
+}
+
+
+/* ----------------------------------------------------------------
+ * misc functions
+ * ----------------------------------------------------------------
+ */
+
+/* usage:
+ * usage help for the bootstrap backend
+ */
+static void
+usage(void)
+{
+ fprintf(stderr,
+ gettext("Usage:\n"
+ " postgres -boot [OPTION]... DBNAME\n"
+ " -c NAME=VALUE set run-time parameter\n"
+ " -d 1-5 debug level\n"
+ " -D datadir data directory\n"
+ " -F turn off fsync\n"
+ " -o file send debug output to file\n"
+ " -x num internal use\n"));
+
+ proc_exit(1);
+}
+
+/*
+ * Set up signal handling for a bootstrap process
+ */
+static void
+bootstrap_signals(void)
+{
+ if (IsUnderPostmaster)
+ {
+ /*
+ * Properly accept or ignore signals the postmaster might send us
+ */
+ pqsignal(SIGHUP, SIG_IGN);
+ pqsignal(SIGINT, SIG_IGN); /* ignore query-cancel */
+ pqsignal(SIGTERM, die);
+ pqsignal(SIGQUIT, quickdie);
+ pqsignal(SIGALRM, SIG_IGN);
+ pqsignal(SIGPIPE, SIG_IGN);
+ pqsignal(SIGUSR1, SIG_IGN);
+ pqsignal(SIGUSR2, SIG_IGN);
+ /*
+ * 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);
+
+ /*
+ * Unblock signals (they were blocked when the postmaster forked
+ * us)
+ */
+ PG_SETMASK(&UnBlockSig);
+ }
+ else
+ {
+ /* Set up appropriately for interactive use */
+ pqsignal(SIGHUP, die);
+ pqsignal(SIGINT, die);
+ pqsignal(SIGTERM, die);
+ pqsignal(SIGQUIT, die);
+ }
+}
+
+/* ----------------
+ * error handling / abort routines
+ * ----------------
+ */
+void
+err_out(void)
+{
+ Warnings++;
+ cleanup();
}
+
/* ----------------------------------------------------------------
* MANUAL BACKEND INTERACTIVE INTERFACE COMMANDS
* ----------------------------------------------------------------
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/libpq/pqsignal.c,v 1.33 2004/04/12 16:19:18 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/libpq/pqsignal.c,v 1.34 2004/05/29 22:48:19 tgl Exp $
*
* NOTES
* This shouldn't be in libpq, but the monitor and some other
#include "libpq/pqsignal.h"
+#ifdef HAVE_SIGPROCMASK
+sigset_t UnBlockSig,
+ BlockSig,
+ AuthBlockSig;
+#else
+int UnBlockSig,
+ BlockSig,
+ AuthBlockSig;
+#endif
+
+
/*
* Initialize BlockSig, UnBlockSig, and AuthBlockSig.
*
return oact.sa_handler;
#endif /* !HAVE_POSIX_SIGNALS */
}
+
#endif /* WIN32 */
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/main/main.c,v 1.84 2004/05/28 05:12:50 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/main/main.c,v 1.85 2004/05/29 22:48:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include <sys/param.h>
#endif
-#include "miscadmin.h"
#include "bootstrap/bootstrap.h"
+#include "miscadmin.h"
+#include "pgstat.h"
+#include "postmaster/postmaster.h"
#include "tcop/tcopprot.h"
#include "utils/help_config.h"
#include "utils/ps_status.h"
-#include "pgstat.h"
#ifdef WIN32
#include "libpq/pqsignal.h"
#endif
#-------------------------------------------------------------------------
#
# Makefile--
-# Makefile for postmaster
+# Makefile for src/backend/postmaster
#
# IDENTIFICATION
-# $PostgreSQL: pgsql/src/backend/postmaster/Makefile,v 1.14 2003/11/29 19:51:55 pgsql Exp $
+# $PostgreSQL: pgsql/src/backend/postmaster/Makefile,v 1.15 2004/05/29 22:48:19 tgl Exp $
#
#-------------------------------------------------------------------------
top_builddir = ../../..
include $(top_builddir)/src/Makefile.global
-OBJS = postmaster.o pgstat.o
+OBJS = postmaster.o bgwriter.o pgstat.o
all: SUBSYS.o
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * bgwriter.c
+ *
+ * The background writer (bgwriter) is new in Postgres 7.5. It attempts
+ * to keep regular backends from having to write out dirty shared buffers
+ * (which they would only do when needing to free a shared buffer to read in
+ * another page). In the best scenario all writes from shared buffers will
+ * be issued by the background writer process. However, regular backends are
+ * still empowered to issue writes if the bgwriter fails to maintain enough
+ * clean shared buffers.
+ *
+ * The bgwriter is also charged with handling all checkpoints. It will
+ * automatically dispatch a checkpoint after a certain amount of time has
+ * elapsed since the last one, and it can be signaled to perform requested
+ * checkpoints as well. (The GUC parameter that mandates a checkpoint every
+ * so many WAL segments is implemented by having backends signal the bgwriter
+ * when they fill WAL segments; the bgwriter itself doesn't watch for the
+ * condition.)
+ *
+ * The bgwriter 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 SIGUSR2, which instructs the bgwriter to execute
+ * a shutdown checkpoint and then exit(0). (All backends must be stopped
+ * before SIGUSR2 is issued!) Emergency termination is by SIGQUIT; like any
+ * backend, the bgwriter will simply abort and exit on SIGQUIT.
+ *
+ * If the bgwriter 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-2003, PostgreSQL Global Development Group
+ *
+ *
+ * IDENTIFICATION
+ * $PostgreSQL: pgsql/src/backend/postmaster/bgwriter.c,v 1.1 2004/05/29 22:48:19 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include <signal.h>
+
+#include "access/xlog.h"
+#include "libpq/pqsignal.h"
+#include "miscadmin.h"
+#include "postmaster/bgwriter.h"
+#include "storage/bufmgr.h"
+#include "storage/freespace.h"
+#include "storage/ipc.h"
+#include "storage/pmsignal.h"
+#include "storage/smgr.h"
+#include "tcop/tcopprot.h"
+#include "utils/guc.h"
+
+
+/*
+ * Shared memory area for communication between bgwriter and backends
+ */
+typedef struct
+{
+ pid_t bgwriter_pid; /* PID of bgwriter (0 if not started) */
+ sig_atomic_t checkpoint_count; /* advances when checkpoint done */
+} BgWriterShmemStruct;
+
+static BgWriterShmemStruct *BgWriterShmem;
+
+/*
+ * GUC parameters
+ */
+int BgWriterDelay = 200;
+int BgWriterPercent = 1;
+int BgWriterMaxPages = 100;
+
+int CheckPointTimeout = 300;
+int CheckPointWarning = 30;
+
+/*
+ * 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 checkpoint_requested = false;
+static volatile sig_atomic_t shutdown_requested = false;
+
+/*
+ * Private state
+ */
+static time_t last_checkpoint_time;
+
+
+static void bg_quickdie(SIGNAL_ARGS);
+static void BgSigHupHandler(SIGNAL_ARGS);
+static void ReqCheckpointHandler(SIGNAL_ARGS);
+static void ReqShutdownHandler(SIGNAL_ARGS);
+
+
+/*
+ * Main entry point for bgwriter process
+ *
+ * This is invoked from BootstrapMain, which has already created the basic
+ * execution environment, but not enabled signals yet.
+ */
+void
+BackgroundWriterMain(void)
+{
+ Assert(BgWriterShmem != NULL);
+ BgWriterShmem->bgwriter_pid = MyProcPid;
+
+ /*
+ * Properly accept or ignore signals the postmaster might send us
+ *
+ * Note: we deliberately ignore SIGTERM, because during a standard Unix
+ * system shutdown cycle, init will SIGTERM all processes at once. We
+ * want to wait for the backends to exit, whereupon the postmaster will
+ * tell us it's okay to shut down (via SIGUSR2).
+ *
+ * SIGUSR1 is presently unused; keep it spare in case someday we want
+ * this process to participate in sinval messaging.
+ */
+ pqsignal(SIGHUP, BgSigHupHandler); /* set flag to read config file */
+ pqsignal(SIGINT, ReqCheckpointHandler); /* request checkpoint */
+ pqsignal(SIGTERM, SIG_IGN); /* ignore SIGTERM */
+ pqsignal(SIGQUIT, bg_quickdie); /* hard crash time */
+ pqsignal(SIGALRM, SIG_IGN);
+ pqsignal(SIGPIPE, SIG_IGN);
+ pqsignal(SIGUSR1, SIG_IGN); /* reserve for sinval */
+ pqsignal(SIGUSR2, ReqShutdownHandler); /* request shutdown */
+
+ /*
+ * 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 */
+#ifdef HAVE_SIGPROCMASK
+ sigdelset(&BlockSig, SIGQUIT);
+#else
+ BlockSig &= ~(sigmask(SIGQUIT));
+#endif
+
+ /*
+ * Initialize so that first time-driven checkpoint happens
+ * at the correct time.
+ */
+ last_checkpoint_time = time(NULL);
+
+ /*
+ * If an exception is encountered, processing resumes here.
+ */
+ if (sigsetjmp(Warn_restart, 1) != 0)
+ {
+ /*
+ * Make sure we're not interrupted while cleaning up. Also forget
+ * any pending QueryCancel request, since we're aborting anyway.
+ * Force InterruptHoldoffCount to a known state in case we
+ * ereport'd from inside a holdoff section.
+ */
+ ImmediateInterruptOK = false;
+ QueryCancelPending = false;
+ InterruptHoldoffCount = 1;
+ CritSectionCount = 0; /* should be unnecessary, but... */
+
+ /*
+ * These operations are really just a minimal subset of
+ * AbortTransaction(). We don't have very many resources
+ * to worry about in bgwriter, but we do have LWLocks and buffers.
+ */
+ LWLockReleaseAll();
+ AbortBufferIO();
+ UnlockBuffers();
+
+ /*
+ * Clear flag to indicate that we got out of error recovery mode
+ * successfully. (Flag was set in elog.c before longjmp().)
+ */
+ InError = false;
+
+ /*
+ * Exit interrupt holdoff section we implicitly established above.
+ */
+ 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. (XXX think about ways to make
+ * progress when the LRU dirty buffer cannot be written...)
+ */
+ pg_usleep(1000000L);
+ }
+
+ Warn_restart_ready = true; /* we can now handle ereport(ERROR) */
+
+ /*
+ * Unblock signals (they were blocked when the postmaster forked us)
+ */
+ PG_SETMASK(&UnBlockSig);
+
+ /*
+ * Loop forever
+ */
+ for (;;)
+ {
+ bool do_checkpoint = false;
+ bool force_checkpoint = false;
+ time_t now;
+ int elapsed_secs;
+ int n;
+ long udelay;
+
+ /*
+ * Process any signals received recently.
+ */
+ if (got_SIGHUP)
+ {
+ got_SIGHUP = false;
+ ProcessConfigFile(PGC_SIGHUP);
+ }
+ if (checkpoint_requested)
+ {
+ checkpoint_requested = false;
+ do_checkpoint = true;
+ force_checkpoint = true;
+ }
+ if (shutdown_requested)
+ {
+ ShutdownXLOG(0, 0);
+ DumpFreeSpaceMap(0, 0);
+ /* Normal exit from the bgwriter is here */
+ proc_exit(0); /* done */
+ }
+
+ /*
+ * Do an unforced checkpoint if too much time has elapsed
+ * since the last one.
+ */
+ now = time(NULL);
+ elapsed_secs = now - last_checkpoint_time;
+ if (elapsed_secs >= CheckPointTimeout)
+ do_checkpoint = true;
+
+ /*
+ * Do a checkpoint if requested, otherwise do one cycle of
+ * dirty-buffer writing.
+ */
+ if (do_checkpoint)
+ {
+ if (CheckPointWarning != 0)
+ {
+ /*
+ * Ideally we should only warn if this checkpoint was
+ * requested due to running out of segment files, and not
+ * if it was manually requested. However we can't tell the
+ * difference with the current signalling mechanism.
+ */
+ if (elapsed_secs < CheckPointWarning)
+ ereport(LOG,
+ (errmsg("checkpoints are occurring too frequently (%d seconds apart)",
+ elapsed_secs),
+ errhint("Consider increasing the configuration parameter \"checkpoint_segments\".")));
+ }
+
+ CreateCheckPoint(false, force_checkpoint);
+
+ /*
+ * Note we record the checkpoint start time not end time as
+ * last_checkpoint_time. This is so that time-driven checkpoints
+ * happen at a predictable spacing.
+ */
+ last_checkpoint_time = now;
+
+ /*
+ * Indicate checkpoint completion to any waiting backends.
+ */
+ BgWriterShmem->checkpoint_count++;
+
+ /*
+ * After any checkpoint, close all smgr files. This is so we
+ * won't hang onto smgr references to deleted files indefinitely.
+ */
+ smgrcloseall();
+
+ /* Nap for configured time before rechecking */
+ n = 1;
+ }
+ else
+ {
+ n = BufferSync(BgWriterPercent, BgWriterMaxPages);
+ }
+
+ /*
+ * Nap for the configured time or sleep for 10 seconds if
+ * there was nothing to do at all.
+ *
+ * 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 = ((n > 0) ? BgWriterDelay : 10000) * 1000L;
+ while (udelay > 1000000L)
+ {
+ if (got_SIGHUP || checkpoint_requested || shutdown_requested)
+ break;
+ pg_usleep(1000000L);
+ udelay -= 1000000L;
+ }
+ if (!(got_SIGHUP || checkpoint_requested || shutdown_requested))
+ pg_usleep(udelay);
+
+ /*
+ * Emergency bailout if postmaster has died. This is to avoid the
+ * necessity for manual cleanup of all postmaster children.
+ */
+ if (!PostmasterIsAlive(true))
+ exit(1);
+ }
+}
+
+
+/* --------------------------------
+ * signal handler routines
+ * --------------------------------
+ */
+
+/*
+ * bg_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
+bg_quickdie(SIGNAL_ARGS)
+{
+ PG_SETMASK(&BlockSig);
+
+ /*
+ * DO NOT proc_exit() -- 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.
+ *
+ * Note we do exit(1) 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.
+ */
+ exit(1);
+}
+
+/* SIGHUP: set flag to re-read config file at next convenient time */
+static void
+BgSigHupHandler(SIGNAL_ARGS)
+{
+ got_SIGHUP = true;
+}
+
+/* SIGINT: set flag to run a normal checkpoint right away */
+static void
+ReqCheckpointHandler(SIGNAL_ARGS)
+{
+ checkpoint_requested = true;
+}
+
+/* SIGUSR2: set flag to run a shutdown checkpoint and exit */
+static void
+ReqShutdownHandler(SIGNAL_ARGS)
+{
+ shutdown_requested = true;
+}
+
+
+/* --------------------------------
+ * communication with backends
+ * --------------------------------
+ */
+
+/*
+ * BgWriterShmemSize
+ * Compute space needed for bgwriter-related shared memory
+ */
+int
+BgWriterShmemSize(void)
+{
+ /*
+ * This is not worth measuring right now, but may become so after we
+ * add fsync signaling ...
+ */
+ return MAXALIGN(sizeof(BgWriterShmemStruct));
+}
+
+/*
+ * BgWriterShmemInit
+ * Allocate and initialize bgwriter-related shared memory
+ */
+void
+BgWriterShmemInit(void)
+{
+ bool found;
+
+ BgWriterShmem = (BgWriterShmemStruct *)
+ ShmemInitStruct("Background Writer Data",
+ sizeof(BgWriterShmemStruct),
+ &found);
+ if (BgWriterShmem == NULL)
+ ereport(FATAL,
+ (errcode(ERRCODE_OUT_OF_MEMORY),
+ errmsg("insufficient shared memory for bgwriter")));
+ if (found)
+ return; /* already initialized */
+
+ MemSet(BgWriterShmem, 0, sizeof(BgWriterShmemStruct));
+}
+
+/*
+ * RequestCheckpoint
+ * Called in backend processes to request an immediate checkpoint
+ *
+ * If waitforit is true, wait until the checkpoint is completed
+ * before returning; otherwise, just signal the request and return
+ * immediately.
+ */
+void
+RequestCheckpoint(bool waitforit)
+{
+ volatile sig_atomic_t *count_ptr = &BgWriterShmem->checkpoint_count;
+ sig_atomic_t old_count = *count_ptr;
+
+ /*
+ * Send signal to request checkpoint. When waitforit is false,
+ * we consider failure to send the signal to be nonfatal.
+ */
+ if (BgWriterShmem->bgwriter_pid == 0)
+ elog(waitforit ? ERROR : LOG,
+ "could not request checkpoint because bgwriter not running");
+ if (kill(BgWriterShmem->bgwriter_pid, SIGINT) != 0)
+ elog(waitforit ? ERROR : LOG,
+ "could not signal for checkpoint: %m");
+
+ /*
+ * If requested, wait for completion. We detect completion by
+ * observing a change in checkpoint_count in shared memory.
+ */
+ if (waitforit)
+ {
+ while (*count_ptr == old_count)
+ {
+ CHECK_FOR_INTERRUPTS();
+ pg_usleep(1000000L);
+ }
+ }
+}
*
* Copyright (c) 2001-2003, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.72 2004/05/28 05:12:58 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.73 2004/05/29 22:48:19 tgl Exp $
* ----------
*/
#include "postgres.h"
#include "pgstat.h"
-#include "access/xact.h"
#include "access/heapam.h"
+#include "access/xact.h"
#include "catalog/catname.h"
-#include "catalog/pg_shadow.h"
#include "catalog/pg_database.h"
-#include "libpq/pqsignal.h"
+#include "catalog/pg_shadow.h"
#include "libpq/libpq.h"
+#include "libpq/pqsignal.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
-#include "utils/memutils.h"
+#include "postmaster/postmaster.h"
#include "storage/backendid.h"
#include "storage/ipc.h"
#include "storage/pg_shmem.h"
+#include "storage/pmsignal.h"
#include "tcop/tcopprot.h"
-#include "utils/rel.h"
#include "utils/hsearch.h"
+#include "utils/memutils.h"
#include "utils/ps_status.h"
+#include "utils/rel.h"
#include "utils/syscache.h"
NON_EXEC_STATIC int pgStatSock = -1;
static int pgStatPipe[2];
static struct sockaddr_storage pgStatAddr;
-static int pgStatPmPipe[2] = {-1, -1};
-static int pgStatCollectorPmPipe[2] = {-1, -1};
static int pgStatPid;
static time_t last_pgstat_start_time;
goto startup_failed;
}
- /*
- * Create the pipe that controls the statistics collector shutdown
- */
- if (pgpipe(pgStatPmPipe) < 0 || pgpipe(pgStatCollectorPmPipe) < 0)
- {
- ereport(LOG,
- (errcode_for_socket_access(),
- errmsg("could not create pipe for statistics collector: %m")));
- goto startup_failed;
- }
-
freeaddrinfo_all(hints.ai_family, addrs);
return;
static pid_t
pgstat_forkexec(STATS_PROCESS_TYPE procType)
{
- char *av[12];
+ char *av[10];
int ac = 0, bufc = 0, i;
- char pgstatBuf[7][32];
+ char pgstatBuf[2][32];
av[ac++] = "postgres";
/* postgres_exec_path is not passed by write_backend_variables */
av[ac++] = postgres_exec_path;
- /* Sockets + pipes (those not passed by write_backend_variables) */
- snprintf(pgstatBuf[bufc++],32,"%d",pgStatPmPipe[0]);
- snprintf(pgstatBuf[bufc++],32,"%d",pgStatPmPipe[1]);
- snprintf(pgstatBuf[bufc++],32,"%d",pgStatCollectorPmPipe[0]);
- snprintf(pgstatBuf[bufc++],32,"%d",pgStatCollectorPmPipe[1]);
+ /* Pipe file ids (those not passed by write_backend_variables) */
snprintf(pgstatBuf[bufc++],32,"%d",pgStatPipe[0]);
snprintf(pgstatBuf[bufc++],32,"%d",pgStatPipe[1]);
static void
pgstat_parseArgs(int argc, char *argv[])
{
- Assert(argc == 10);
+ Assert(argc == 6);
argc = 3;
StrNCpy(postgres_exec_path, argv[argc++], MAXPGPATH);
- pgStatPmPipe[0] = atoi(argv[argc++]);
- pgStatPmPipe[1] = atoi(argv[argc++]);
- pgStatCollectorPmPipe[0] = atoi(argv[argc++]);
- pgStatCollectorPmPipe[1] = atoi(argv[argc++]);
pgStatPipe[0] = atoi(argv[argc++]);
pgStatPipe[1] = atoi(argv[argc++]);
}
/* Specific beos actions after backend startup */
beos_backend_startup();
#endif
- /* Close the postmaster's sockets, except for pgstat link */
- ClosePostmasterPorts(false);
+ /* Close the postmaster's sockets */
+ ClosePostmasterPorts();
/* Drop our connection to postmaster's shared memory, as well */
PGSharedMemoryDetach();
}
-/* ----------
- * pgstat_close_sockets() -
- *
- * Called when postmaster forks a non-pgstat child process, to close off
- * file descriptors that should not be held open in child processes.
- * ----------
- */
-void
-pgstat_close_sockets(void)
-{
- if (pgStatPmPipe[0] >= 0)
- closesocket(pgStatPmPipe[0]);
- pgStatPmPipe[0] = -1;
- if (pgStatPmPipe[1] >= 0)
- closesocket(pgStatPmPipe[1]);
- pgStatPmPipe[1] = -1;
- if (pgStatCollectorPmPipe[0] >= 0)
- closesocket(pgStatCollectorPmPipe[0]);
- pgStatCollectorPmPipe[0] = -1;
- if (pgStatCollectorPmPipe[1] >= 0)
- closesocket(pgStatCollectorPmPipe[1]);
- pgStatCollectorPmPipe[1] = -1;
-}
-
-
/* ----------
* pgstat_beterm() -
*
pgstat_parseArgs(argc,argv);
#endif
- /*
- * Close the writing end of the postmaster pipe, so we'll see it
- * closing when the postmaster terminates and can terminate as well.
- */
- closesocket(pgStatPmPipe[1]);
- pgStatPmPipe[1] = -1;
- closesocket(pgStatCollectorPmPipe[1]);
- pgStatCollectorPmPipe[1] = -1;
-
/*
* Start a buffering process to read from the socket, so we have a
* little more time to process incoming messages.
PgStat_Msg msg;
fd_set rfds;
int readPipe;
- int pmPipe;
int nready;
int len = 0;
struct timeval timeout;
/* Close unwanted files */
closesocket(pgStatPipe[1]);
closesocket(pgStatSock);
- pmPipe = pgStatCollectorPmPipe[0];
/*
* Identify myself via ps
* shutdown, we want to save the final stats to reuse at next startup.
* But if the buffer process failed, it seems best not to (there may
* even now be a new collector firing up, and we don't want it to read
- * a partially- rewritten stats file). We can tell whether the
- * postmaster is still alive by checking to see if the postmaster pipe
- * is still open. If it is read-ready (ie, EOF), the postmaster must
- * have quit.
- */
- FD_ZERO(&rfds);
- FD_SET(pmPipe, &rfds);
- timeout.tv_sec = 0;
- timeout.tv_usec = 0;
- nready = select(pmPipe+1,&rfds,NULL,NULL,&timeout);
- if (nready > 0 && FD_ISSET(pmPipe, &rfds))
+ * a partially-rewritten stats file).
+ */
+ if (!PostmasterIsAlive(false))
pgstat_write_statsfile();
}
{
fd_set rfds;
fd_set wfds;
+ struct timeval timeout;
int writePipe = pgStatPipe[1];
- int pmPipe = pgStatPmPipe[0];
int maxfd;
int nready;
int len;
/*
* If we have messages to write out, we add the pipe to the write
- * descriptor set. Otherwise, we check if the postmaster might
- * have terminated.
+ * descriptor set.
*/
if (msg_have > 0)
{
if (writePipe > maxfd)
maxfd = writePipe;
}
- else
- {
- FD_SET(pmPipe, &rfds);
- if (pmPipe > maxfd)
- maxfd = pmPipe;
- }
/*
- * Wait for some work to do.
+ * Wait for some work to do; but not for more than 10 seconds
+ * (this determines how quickly we will shut down after postmaster
+ * termination).
*/
- nready = select(maxfd + 1, &rfds, &wfds, NULL, NULL);
+ timeout.tv_sec = 10;
+ timeout.tv_usec = 0;
+
+ nready = select(maxfd + 1, &rfds, &wfds, NULL, &timeout);
if (nready < 0)
{
if (errno == EINTR)
continue;
/*
- * If the pipe from the postmaster is ready for reading, the
- * kernel must have closed it on exit() (the postmaster never
- * really writes to it). So we've done our job.
+ * If the postmaster has terminated, we've done our job.
*/
- if (FD_ISSET(pmPipe, &rfds))
+ if (!PostmasterIsAlive(true))
exit(0);
}
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.399 2004/05/28 15:14:03 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.400 2004/05/29 22:48:19 tgl Exp $
*
* NOTES
*
* Initialization:
- * The Postmaster sets up a few shared memory data structures
- * for the backends. It should at the very least initialize the
- * lock manager.
+ * The Postmaster sets up shared memory data structures
+ * for the backends.
*
* Synchronization:
* The Postmaster shares memory with the backends but should avoid
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "nodes/nodes.h"
+#include "postmaster/postmaster.h"
#include "pgtime.h"
#include "storage/fd.h"
#include "storage/ipc.h"
#include "pgstat.h"
-#ifdef HAVE_SIGPROCMASK
-sigset_t UnBlockSig,
- BlockSig,
- AuthBlockSig;
-
-#else
-int UnBlockSig,
- BlockSig,
- AuthBlockSig;
-#endif
-
/*
* List of active backends (or child processes anyway; we don't actually
* know whether a given child has become a backend or is still in the
* authorization phase). This is used mainly to keep track of how many
* children we have and send them appropriate signals when necessary.
+ *
+ * "Special" children such as the startup and bgwriter tasks are not in
+ * this list.
*/
typedef struct bkend
{
char *UnixSocketDir;
char *ListenAddresses;
-/*
- * MaxBackends is the limit on the number of backends we can start.
- * Note that a larger MaxBackends value will increase the size of the
- * shared memory area as well as cause the postmaster to grab more
- * kernel semaphores, even if you never actually use that many
- * backends.
- */
-int MaxBackends;
-
/*
* ReservedBackends is the number of backends reserved for superuser use.
* This number is taken out of the pool size given by MaxBackends so
int PreAuthDelay = 0;
int AuthenticationTimeout = 60;
-int CheckPointTimeout = 300;
-int CheckPointWarning = 30;
-time_t LastSignalledCheckpoint = 0;
bool log_hostname; /* for ps display and logging */
bool Log_connections = false;
/* list of library:init-function to be preloaded */
char *preload_libraries_string = NULL;
-/* Startup/shutdown state */
+/* PIDs of special child processes; 0 when not running */
static pid_t StartupPID = 0,
- ShutdownPID = 0,
- CheckPointPID = 0,
BgWriterPID = 0;
-static time_t checkpointed = 0;
+/* Startup/shutdown state */
#define NoShutdown 0
#define SmartShutdown 1
#define FastShutdown 2
* Also, the global MyCancelKey passes the cancel key assigned to a given
* backend from the postmaster to that backend (via fork).
*/
-
static unsigned int random_seed = 0;
static int debug_flag = 0;
static void sigusr1_handler(SIGNAL_ARGS);
static void dummy_handler(SIGNAL_ARGS);
static void CleanupProc(int pid, int exitstatus);
+static void HandleChildCrash(int pid, int exitstatus);
static void LogChildExit(int lev, const char *procname,
int pid, int exitstatus);
static int BackendRun(Port *port);
static void SignalChildren(int signal);
static int CountChildren(void);
static bool CreateOptsFile(int argc, char *argv[], char *fullprogname);
-static pid_t SSDataBase(int xlop);
+static pid_t StartChildProcess(int xlop);
static void
postmaster_error(const char *fmt,...)
/* This lets gcc check the format string for consistency. */
#endif /* EXEC_BACKEND */
-#define StartupDataBase() SSDataBase(BS_XLOG_STARTUP)
-#define CheckPointDataBase() SSDataBase(BS_XLOG_CHECKPOINT)
-#define StartBackgroundWriter() SSDataBase(BS_XLOG_BGWRITER)
-#define ShutdownDataBase() SSDataBase(BS_XLOG_SHUTDOWN)
+#define StartupDataBase() StartChildProcess(BS_XLOG_STARTUP)
+#define StartBackgroundWriter() StartChildProcess(BS_XLOG_BGWRITER)
/*
{
int opt;
int status;
- char original_extraoptions[MAXPGPATH];
char *potential_DataDir = NULL;
int i;
- *original_extraoptions = '\0';
-
progname = get_progname(argv[0]);
+ MyProcPid = PostmasterPid = getpid();
+
IsPostmasterEnvironment = true;
/*
*/
umask((mode_t) 0077);
- MyProcPid = PostmasterPid = getpid();
-
/*
* Fire up essential subsystems: memory management
*/
case 'o':
/*
- * Other options to pass to the backend on the command
- * line -- useful only for debugging.
+ * Other options to pass to the backend on the command line
*/
strcat(ExtraOptions, " ");
strcat(ExtraOptions, optarg);
- strcpy(original_extraoptions, optarg);
break;
case 'p':
SetConfigOption("port", optarg, PGC_POSTMASTER, PGC_S_ARGV);
* We want to do this before we try to grab the input sockets, because
* the data directory interlock is more reliable than the socket-file
* interlock (thanks to whoever decided to put socket files in /tmp
- * :-(). For the same reason, it's best to grab the TCP socket before
+ * :-(). For the same reason, it's best to grab the TCP socket(s) before
* the Unix socket.
*/
CreateDataDirLockFile(DataDir, true);
BackendList = DLNewList();
#ifdef WIN32
-
/*
- * Initialize the child pid/HANDLE arrays
+ * Initialize the child pid/HANDLE arrays for signal handling.
*/
- win32_childPIDArray = (pid_t *) malloc(NUM_BACKENDARRAY_ELEMS * sizeof(pid_t));
- win32_childHNDArray = (HANDLE *) malloc(NUM_BACKENDARRAY_ELEMS * sizeof(HANDLE));
+ win32_childPIDArray = (pid_t *)
+ malloc(NUM_BACKENDARRAY_ELEMS * sizeof(pid_t));
+ win32_childHNDArray = (HANDLE *)
+ malloc(NUM_BACKENDARRAY_ELEMS * sizeof(HANDLE));
if (!win32_childPIDArray || !win32_childHNDArray)
ereport(FATAL,
(errcode(ERRCODE_OUT_OF_MEMORY),
*
* CAUTION: when changing this list, check for side-effects on the signal
* handling setup of child processes. See tcop/postgres.c,
- * bootstrap/bootstrap.c, and postmaster/pgstat.c.
+ * bootstrap/bootstrap.c, postmaster/bgwriter.c, and postmaster/pgstat.c.
*/
pqinitmask();
PG_SETMASK(&BlockSig);
pqsignal(SIGHUP, SIGHUP_handler); /* reread config file and have
* children do same */
- pqsignal(SIGINT, pmdie); /* send SIGTERM and ShutdownDataBase */
+ pqsignal(SIGINT, pmdie); /* send SIGTERM and shut down */
pqsignal(SIGQUIT, pmdie); /* send SIGQUIT and die */
- pqsignal(SIGTERM, pmdie); /* wait for children and ShutdownDataBase */
+ pqsignal(SIGTERM, pmdie); /* wait for children and shut down */
pqsignal(SIGALRM, SIG_IGN); /* ignored */
pqsignal(SIGPIPE, SIG_IGN); /* ignored */
pqsignal(SIGUSR1, sigusr1_handler); /* message from child process */
*/
whereToSendOutput = None;
- /*
- * On many platforms, the first call of localtime() incurs significant
- * overhead to load timezone info from the system configuration files.
- * By doing it once in the postmaster, we avoid having to do it in
- * every started child process. The savings are not huge, but they
- * add up...
- */
- {
- time_t now = time(NULL);
-
- (void) pg_localtime(&now);
- }
-
/*
* Initialize and try to startup the statistics collector process
*/
static void
pmdaemonize(void)
{
-#ifdef WIN32
- /* not supported */
- elog(FATAL, "SilentMode not supported under WIN32");
-#else
+#ifndef WIN32
int i;
pid_t pid;
setitimer(ITIMER_PROF, &prof_itimer, NULL);
#endif
- MyProcPid = getpid(); /* reset MyProcPid to child */
+ MyProcPid = PostmasterPid = getpid(); /* reset PID vars to child */
/* GH: If there's no setsid(), we hopefully don't need silent mode.
* Until there's a better solution.
dup2(i, 1);
dup2(i, 2);
close(i);
-#endif
+#else /* WIN32 */
+ /* not supported */
+ elog(FATAL, "SilentMode not supported under WIN32");
+#endif /* WIN32 */
}
/*
- * Main loop of postmaster
+ * Main idle loop of postmaster
*/
static int
ServerLoop(void)
{
fd_set readmask;
int nSockets;
- struct timeval now,
+ time_t now,
+ last_touch_time;
+ struct timeval earlier,
later;
struct timezone tz;
- int i;
- gettimeofday(&now, &tz);
+ gettimeofday(&earlier, &tz);
+ last_touch_time = time(NULL);
nSockets = initMasks(&readmask);
Port *port;
fd_set rmask;
struct timeval timeout;
+ int selres;
+ int i;
/*
- * The timeout for the select() below is normally set on the basis
- * of the time to the next checkpoint. However, if for some
- * reason we don't have a next-checkpoint time, time out after 60
- * seconds. This keeps checkpoint scheduling from locking up when
- * we get new connection requests infrequently (since we are
- * likely to detect checkpoint completion just after enabling
- * signals below, after we've already made the decision about how
- * long to wait this time).
+ * Wait for something to happen.
+ *
+ * We wait at most one minute, to ensure that the other background
+ * tasks handled below get done even when no requests are arriving.
*/
+ memcpy((char *) &rmask, (char *) &readmask, sizeof(fd_set));
+
timeout.tv_sec = 60;
timeout.tv_usec = 0;
- if (CheckPointPID == 0 && checkpointed &&
- StartupPID == 0 && Shutdown == NoShutdown &&
- !FatalError && random_seed != 0)
- {
- time_t now = time(NULL);
-
- if (CheckPointTimeout + checkpointed > now)
- {
- /*
- * Not time for checkpoint yet, so set select timeout
- */
- timeout.tv_sec = CheckPointTimeout + checkpointed - now;
- }
- else
- {
- /* Time to make the checkpoint... */
- CheckPointPID = CheckPointDataBase();
-
- /*
- * if fork failed, schedule another try at 0.1 normal
- * delay
- */
- if (CheckPointPID == 0)
- {
- timeout.tv_sec = CheckPointTimeout / 10;
- checkpointed = now + timeout.tv_sec - CheckPointTimeout;
- }
- }
- }
+ PG_SETMASK(&UnBlockSig);
- /*
- * If no background writer process is running and we should do
- * background writing, start one. It doesn't matter if this fails,
- * we'll just try again later.
- */
- if (BgWriterPID == 0 && BgWriterPercent > 0 &&
- StartupPID == 0 && Shutdown == NoShutdown &&
- !FatalError && random_seed != 0)
- BgWriterPID = StartBackgroundWriter();
+ selres = select(nSockets, &rmask, NULL, NULL, &timeout);
/*
- * Wait for something to happen.
+ * Block all signals until we wait again. (This makes it safe for
+ * our signal handlers to do nontrivial work.)
*/
- memcpy((char *) &rmask, (char *) &readmask, sizeof(fd_set));
-
- PG_SETMASK(&UnBlockSig);
+ PG_SETMASK(&BlockSig);
- if (select(nSockets, &rmask, NULL, NULL, &timeout) < 0)
+ if (selres < 0)
{
- PG_SETMASK(&BlockSig);
if (errno == EINTR || errno == EWOULDBLOCK)
continue;
ereport(LOG,
}
/*
- * Block all signals until we wait again. (This makes it safe for
- * our signal handlers to do nontrivial work.)
- */
- PG_SETMASK(&BlockSig);
-
- /*
- * Select a random seed at the time of first receiving a request.
+ * New connection pending on any of our sockets? If so, fork a
+ * child process to deal with it.
*/
- while (random_seed == 0)
+ if (selres > 0)
{
- gettimeofday(&later, &tz);
-
/*
- * We are not sure how much precision is in tv_usec, so we
- * swap the nibbles of 'later' and XOR them with 'now'. On the
- * off chance that the result is 0, we loop until it isn't.
+ * Select a random seed at the time of first receiving a request.
*/
- random_seed = now.tv_usec ^
- ((later.tv_usec << 16) |
- ((later.tv_usec >> 16) & 0xffff));
- }
+ while (random_seed == 0)
+ {
+ gettimeofday(&later, &tz);
- /*
- * New connection pending on any of our sockets? If so, fork a
- * child process to deal with it.
- */
- for (i = 0; i < MAXLISTEN; i++)
- {
- if (ListenSocket[i] == -1)
- break;
- if (FD_ISSET(ListenSocket[i], &rmask))
+ /*
+ * We are not sure how much precision is in tv_usec, so we
+ * swap the nibbles of 'later' and XOR them with 'earlier'. On
+ * the off chance that the result is 0, we loop until it isn't.
+ */
+ random_seed = earlier.tv_usec ^
+ ((later.tv_usec << 16) |
+ ((later.tv_usec >> 16) & 0xffff));
+ }
+
+ for (i = 0; i < MAXLISTEN; i++)
{
- port = ConnCreate(ListenSocket[i]);
- if (port)
+ if (ListenSocket[i] == -1)
+ break;
+ if (FD_ISSET(ListenSocket[i], &rmask))
{
- BackendStartup(port);
-
- /*
- * We no longer need the open socket or port structure
- * in this process
- */
- StreamClose(port->sock);
- ConnFree(port);
+ port = ConnCreate(ListenSocket[i]);
+ if (port)
+ {
+ BackendStartup(port);
+
+ /*
+ * We no longer need the open socket or port structure
+ * in this process
+ */
+ StreamClose(port->sock);
+ ConnFree(port);
+ }
}
}
}
+ /*
+ * If no background writer process is running, and we are not in
+ * a state that prevents it, start one. It doesn't matter if this
+ * fails, we'll just try again later.
+ */
+ if (BgWriterPID == 0 && StartupPID == 0 && !FatalError)
+ {
+ BgWriterPID = StartBackgroundWriter();
+ /* If shutdown is pending, set it going */
+ if (Shutdown > NoShutdown && BgWriterPID != 0)
+ kill(BgWriterPID, SIGUSR2);
+ }
+
/* If we have lost the stats collector, try to start a new one */
if (!pgstat_is_running)
pgstat_start();
+
+ /*
+ * Touch the socket and lock file at least every ten minutes, to ensure
+ * that they are not removed by overzealous /tmp-cleaning tasks.
+ */
+ now = time(NULL);
+ if (now - last_touch_time >= 10 * 60)
+ {
+ TouchSocketFile();
+ TouchSocketLockFile();
+ last_touch_time = now;
+ }
}
}
/*
- * Initialise the masks for select() for the ports
- * we are listening on. Return the number of sockets to listen on.
+ * Initialise the masks for select() for the ports we are listening on.
+ * Return the number of sockets to listen on.
*/
static int
initMasks(fd_set *rmask)
backendPID = (int) ntohl(canc->backendPID);
cancelAuthCode = (long) ntohl(canc->cancelAuthCode);
- if (backendPID == CheckPointPID)
- {
- ereport(DEBUG2,
- (errmsg_internal("ignoring cancel request for checkpoint process %d",
- backendPID)));
- return;
- }
- else if (backendPID == BgWriterPID)
+ if (backendPID == BgWriterPID)
{
ereport(DEBUG2,
(errmsg_internal("ignoring cancel request for bgwriter process %d",
/*
* See if we have a matching backend. In the EXEC_BACKEND case, we
* can no longer access the postmaster's own backend list, and must
- * rely on the backup array in shared memory.
+ * rely on the duplicate array in shared memory.
*/
#ifndef EXEC_BACKEND
for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr))
* them open, of course.
*/
void
-ClosePostmasterPorts(bool pgstat_too)
+ClosePostmasterPorts(void)
{
int i;
ListenSocket[i] = -1;
}
}
-
- /* Close pgstat control sockets, unless we're starting pgstat itself */
- if (pgstat_too)
- pgstat_close_sockets();
}
(errmsg("received SIGHUP, reloading configuration files")));
ProcessConfigFile(PGC_SIGHUP);
SignalChildren(SIGHUP);
+ if (BgWriterPID != 0)
+ kill(BgWriterPID, SIGHUP);
load_hba();
load_ident();
/* Update the starting-point file for future children */
write_nondefault_variables(PGC_SIGHUP);
#endif
-
- /*
- * Tell the background writer to terminate so that we will start a
- * new one with a possibly changed config
- */
- if (BgWriterPID != 0)
- kill(BgWriterPID, SIGTERM);
}
PG_SETMASK(&UnBlockSig);
switch (postgres_signal_arg)
{
case SIGTERM:
-
/*
* Smart Shutdown:
*
- * Wait for children to end their work and ShutdownDataBase.
+ * Wait for children to end their work, then shut down.
*/
if (Shutdown >= SmartShutdown)
break;
ereport(LOG,
(errmsg("received smart shutdown request")));
- /* Must tell bgwriter to quit, or it never will... */
- if (BgWriterPID != 0)
- kill(BgWriterPID, SIGTERM);
-
- if (DLGetHead(BackendList)) /* let reaper() handle this */
- break;
+ if (DLGetHead(BackendList))
+ break; /* let reaper() handle this */
/*
- * No children left. Shutdown data base system.
+ * No children left. Begin shutdown of data base system.
*/
- if (StartupPID > 0 || FatalError) /* let reaper() handle
- * this */
- break;
- if (ShutdownPID > 0)
- {
- elog(PANIC, "shutdown process %d already running",
- (int) ShutdownPID);
- abort();
- }
-
- ShutdownPID = ShutdownDataBase();
+ if (StartupPID != 0 || FatalError)
+ break; /* let reaper() handle this */
+ /* Start the bgwriter if not running */
+ if (BgWriterPID == 0)
+ BgWriterPID = StartBackgroundWriter();
+ /* And tell it to shut down */
+ if (BgWriterPID != 0)
+ kill(BgWriterPID, SIGUSR2);
break;
case SIGINT:
-
/*
* Fast Shutdown:
*
* Abort all children with SIGTERM (rollback active transactions
- * and exit) and ShutdownDataBase when they are gone.
+ * and exit) and shut down when they are gone.
*/
if (Shutdown >= FastShutdown)
break;
}
/*
- * No children left. Shutdown data base system.
+ * No children left. Begin shutdown of data base system.
*
- * Unlike the previous case, it is not an error for the shutdown
- * process to be running already (we could get SIGTERM
- * followed shortly later by SIGINT).
+ * Note: if we previously got SIGTERM then we may send SIGUSR2
+ * to the bgwriter a second time here. This should be harmless.
*/
- if (StartupPID > 0 || FatalError) /* let reaper() handle
- * this */
- break;
- if (ShutdownPID == 0)
- ShutdownPID = ShutdownDataBase();
+ if (StartupPID != 0 || FatalError)
+ break; /* let reaper() handle this */
+ /* Start the bgwriter if not running */
+ if (BgWriterPID == 0)
+ BgWriterPID = StartBackgroundWriter();
+ /* And tell it to shut down */
+ if (BgWriterPID != 0)
+ kill(BgWriterPID, SIGUSR2);
break;
case SIGQUIT:
-
/*
* Immediate Shutdown:
*
* abort all children with SIGQUIT and exit without attempt to
- * properly shutdown data base system.
+ * properly shut down data base system.
*/
ereport(LOG,
(errmsg("received immediate shutdown request")));
- if (ShutdownPID > 0)
- kill(ShutdownPID, SIGQUIT);
- if (StartupPID > 0)
+ if (StartupPID != 0)
kill(StartupPID, SIGQUIT);
+ if (BgWriterPID != 0)
+ kill(BgWriterPID, SIGQUIT);
if (DLGetHead(BackendList))
SignalChildren(SIGQUIT);
ExitPostmaster(0);
}
/*
- * Check if this child was a shutdown or startup process.
+ * Check if this child was a startup process.
*/
- if (ShutdownPID > 0 && pid == ShutdownPID)
- {
- if (exitstatus != 0)
- {
- LogChildExit(LOG, gettext("shutdown process"),
- pid, exitstatus);
- ExitPostmaster(1);
- }
- /* Normal postmaster exit is here */
- ExitPostmaster(0);
- }
-
- if (StartupPID > 0 && pid == StartupPID)
+ if (StartupPID != 0 && pid == StartupPID)
{
+ StartupPID = 0;
if (exitstatus != 0)
{
LogChildExit(LOG, gettext("startup process"),
(errmsg("aborting startup due to startup process failure")));
ExitPostmaster(1);
}
- StartupPID = 0;
/*
* Startup succeeded - we are done with system startup or recovery.
FatalError = false;
/*
- * Arrange for first checkpoint to occur after standard delay.
+ * Crank up the background writer. It doesn't matter if this
+ * fails, we'll just try again later.
*/
- CheckPointPID = 0;
- checkpointed = time(NULL);
+ Assert(BgWriterPID == 0);
+ BgWriterPID = StartBackgroundWriter();
/*
* Go to shutdown mode if a shutdown request was pending.
*/
- if (Shutdown > NoShutdown)
+ if (Shutdown > NoShutdown && BgWriterPID != 0)
+ kill(BgWriterPID, SIGUSR2);
+
+ continue;
+ }
+
+ /*
+ * Was it the bgwriter?
+ */
+ if (BgWriterPID != 0 && pid == BgWriterPID)
+ {
+ if (exitstatus == 0 && Shutdown > NoShutdown &&
+ !FatalError && !DLGetHead(BackendList))
{
- if (ShutdownPID > 0)
- {
- elog(PANIC, "startup process %d died while shutdown process %d already running",
- pid, (int) ShutdownPID);
- abort();
- }
- ShutdownPID = ShutdownDataBase();
+ /*
+ * Normal postmaster exit is here: we've seen normal
+ * exit of the bgwriter after it's been told to shut down.
+ * We expect that it wrote a shutdown checkpoint. (If
+ * for some reason it didn't, recovery will occur on next
+ * postmaster start.)
+ */
+ ExitPostmaster(0);
}
-
- goto reaper_done;
+ /*
+ * Any unexpected exit of the bgwriter is treated as a crash.
+ */
+ LogChildExit(DEBUG2, gettext("background writer process"),
+ pid, exitstatus);
+ HandleChildCrash(pid, exitstatus);
+ continue;
}
/*
- * Else do standard child cleanup.
+ * Else do standard backend child cleanup.
*/
CleanupProc(pid, exitstatus);
-
} /* loop over pending child-death reports */
if (FatalError)
* Wait for all children exit, then reset shmem and
* StartupDataBase.
*/
- if (DLGetHead(BackendList) || StartupPID > 0 || ShutdownPID > 0)
+ if (DLGetHead(BackendList) || StartupPID != 0 || BgWriterPID != 0)
goto reaper_done;
ereport(LOG,
(errmsg("all server processes terminated; reinitializing")));
if (Shutdown > NoShutdown)
{
- if (DLGetHead(BackendList))
- goto reaper_done;
- if (StartupPID > 0 || ShutdownPID > 0)
+ if (DLGetHead(BackendList) || StartupPID != 0)
goto reaper_done;
- ShutdownPID = ShutdownDataBase();
+ /* Start the bgwriter if not running */
+ if (BgWriterPID == 0)
+ BgWriterPID = StartBackgroundWriter();
+ /* And tell it to shut down */
+ if (BgWriterPID != 0)
+ kill(BgWriterPID, SIGUSR2);
}
reaper_done:
CleanupProc(int pid,
int exitstatus) /* child's exit status. */
{
- Dlelem *curr,
- *next;
- Backend *bp;
+ Dlelem *curr;
- LogChildExit(DEBUG2, gettext("child process"), pid, exitstatus);
+ LogChildExit(DEBUG2, gettext("server process"), pid, exitstatus);
/*
* If a backend dies in an ugly way (i.e. exit status not 0) then we
* we assume everything is hunky dory and simply remove the backend
* from the active backend list.
*/
- if (exitstatus == 0)
+ if (exitstatus != 0)
+ {
+ HandleChildCrash(pid, exitstatus);
+ return;
+ }
+
+ for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr))
{
- curr = DLGetHead(BackendList);
- while (curr)
+ Backend *bp = (Backend *) DLE_VAL(curr);
+
+ if (bp->pid == pid)
{
- bp = (Backend *) DLE_VAL(curr);
- if (bp->pid == pid)
- {
+ DLRemove(curr);
+ free(bp);
+ DLFreeElem(curr);
#ifdef EXEC_BACKEND
- ShmemBackendArrayRemove(bp->pid);
+ ShmemBackendArrayRemove(pid);
#endif
- DLRemove(curr);
- free(bp);
- DLFreeElem(curr);
- break;
- }
- curr = DLGetSucc(curr);
- }
-
- if (pid == CheckPointPID)
- {
- CheckPointPID = 0;
- if (!FatalError)
- {
- checkpointed = time(NULL);
- }
- }
- else if (pid == BgWriterPID)
- BgWriterPID = 0;
- else
+ /* Tell the collector about backend termination */
pgstat_beterm(pid);
-
- return;
+ break;
+ }
}
+}
- /* below here we're dealing with a non-normal exit */
+/*
+ * HandleChildCrash -- cleanup after failed backend or bgwriter.
+ *
+ * The objectives here are to clean up our local state about the child
+ * process, and to signal all other remaining children to quickdie.
+ */
+static void
+HandleChildCrash(int pid,
+ int exitstatus) /* child's exit status. */
+{
+ Dlelem *curr,
+ *next;
+ Backend *bp;
- /* Make log entry unless we did so already */
+ /*
+ * Make log entry unless there was a previous crash (if so, nonzero
+ * exit status is to be expected in SIGQUIT response; don't clutter log)
+ */
if (!FatalError)
{
LogChildExit(LOG,
- (pid == CheckPointPID) ? gettext("checkpoint process") :
- (pid == BgWriterPID) ? gettext("bgwriter process") :
+ (pid == BgWriterPID) ?
+ gettext("background writer process") :
gettext("server process"),
pid, exitstatus);
ereport(LOG,
- (errmsg("terminating any other active server processes")));
+ (errmsg("terminating any other active server processes")));
}
- curr = DLGetHead(BackendList);
- while (curr)
+ /* Process regular backends */
+ for (curr = DLGetHead(BackendList); curr; curr = next)
{
next = DLGetSucc(curr);
bp = (Backend *) DLE_VAL(curr);
- if (bp->pid != pid)
+ if (bp->pid == pid)
+ {
+ /*
+ * Found entry for freshly-dead backend, so remove it.
+ */
+ DLRemove(curr);
+ free(bp);
+ DLFreeElem(curr);
+#ifdef EXEC_BACKEND
+ ShmemBackendArrayRemove(pid);
+#endif
+ /* Tell the collector about backend termination */
+ pgstat_beterm(pid);
+ /* Keep looping so we can signal remaining backends */
+ }
+ else
{
/*
* This backend is still alive. Unless we did so already,
kill(bp->pid, (SendStop ? SIGSTOP : SIGQUIT));
}
}
- else
- {
- /*
- * Found entry for freshly-dead backend, so remove it.
- */
-#ifdef EXEC_BACKEND
- ShmemBackendArrayRemove(bp->pid);
-#endif
- DLRemove(curr);
- free(bp);
- DLFreeElem(curr);
- }
- curr = next;
}
- if (pid == CheckPointPID)
- {
- CheckPointPID = 0;
- checkpointed = 0;
- }
- else if (pid == BgWriterPID)
+ /* Take care of the bgwriter too */
+ if (pid == BgWriterPID)
BgWriterPID = 0;
- else
+ else if (BgWriterPID != 0 && !FatalError)
{
- /*
- * Tell the collector about backend termination
- */
- pgstat_beterm(pid);
+ ereport(DEBUG2,
+ (errmsg_internal("sending %s to process %d",
+ (SendStop ? "SIGSTOP" : "SIGQUIT"),
+ (int) BgWriterPID)));
+ kill(BgWriterPID, (SendStop ? SIGSTOP : SIGQUIT));
}
FatalError = true;
static void
SignalChildren(int signal)
{
- Dlelem *curr,
- *next;
- Backend *bp;
+ Dlelem *curr;
- curr = DLGetHead(BackendList);
- while (curr)
+ for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr))
{
- next = DLGetSucc(curr);
- bp = (Backend *) DLE_VAL(curr);
+ Backend *bp = (Backend *) DLE_VAL(curr);
- if (bp->pid != MyProcPid)
- {
- ereport(DEBUG2,
- (errmsg_internal("sending signal %d to process %d",
- signal,
- (int) bp->pid)));
- kill(bp->pid, signal);
- }
-
- curr = next;
+ ereport(DEBUG4,
+ (errmsg_internal("sending signal %d to process %d",
+ signal, (int) bp->pid)));
+ kill(bp->pid, signal);
}
}
*/
bn->pid = pid;
bn->cancel_key = MyCancelKey;
+ DLAddHead(BackendList, DLNewElem(bn));
#ifdef EXEC_BACKEND
ShmemBackendArrayAdd(bn);
#endif
- DLAddHead(BackendList, DLNewElem(bn));
return STATUS_OK;
}
/*
* Let's clean up ourselves as the postmaster child, and close the
- * postmaster's other sockets
+ * postmaster's listen sockets
*/
- ClosePostmasterPorts(true);
+ ClosePostmasterPorts();
/* We don't want the postmaster's proc_exit() handlers */
on_exit_reset();
if (strcmp(argv[1], "-forkboot") == 0)
{
/* Close the postmaster's sockets */
- ClosePostmasterPorts(true);
+ ClosePostmasterPorts();
/* Attach process to shared segments */
CreateSharedMemoryAndSemaphores(false, MaxBackends, 0);
BootstrapMain(argc - 2, argv + 2);
- ExitPostmaster(0);
+ proc_exit(0);
}
if (strcmp(argv[1], "-forkbuf") == 0)
{
/* Close the postmaster's sockets */
- ClosePostmasterPorts(false);
+ ClosePostmasterPorts();
/* Do not want to attach to shared memory */
PgstatBufferMain(argc, argv);
- ExitPostmaster(0);
+ proc_exit(0);
}
if (strcmp(argv[1], "-forkcol") == 0)
{
/* Do not want to attach to shared memory */
PgstatCollectorMain(argc, argv);
- ExitPostmaster(0);
+ proc_exit(0);
}
return 1; /* shouldn't get here */
*
* MUST -- vadim 05-10-1999
*/
- /* Should I use true instead? */
- ClosePostmasterPorts(false);
proc_exit(status);
}
PG_SETMASK(&BlockSig);
- if (CheckPostmasterSignal(PMSIGNAL_DO_CHECKPOINT))
- {
- if (CheckPointWarning != 0)
- {
- /*
- * This only times checkpoints forced by running out of
- * segment files. Other checkpoints could reduce the
- * frequency of forced checkpoints.
- */
- time_t now = time(NULL);
-
- if (LastSignalledCheckpoint != 0)
- {
- int elapsed_secs = now - LastSignalledCheckpoint;
-
- if (elapsed_secs < CheckPointWarning)
- ereport(LOG,
- (errmsg("checkpoints are occurring too frequently (%d seconds apart)",
- elapsed_secs),
- errhint("Consider increasing the configuration parameter \"checkpoint_segments\".")));
- }
- LastSignalledCheckpoint = now;
- }
-
- /*
- * Request to schedule a checkpoint
- *
- * Ignore request if checkpoint is already running or checkpointing
- * is currently disabled
- */
- if (CheckPointPID == 0 && checkpointed &&
- StartupPID == 0 && Shutdown == NoShutdown &&
- !FatalError && random_seed != 0)
- {
- CheckPointPID = CheckPointDataBase();
- /* note: if fork fails, CheckPointPID stays 0; nothing happens */
- }
- }
-
if (CheckPostmasterSignal(PMSIGNAL_PASSWORD_CHANGE))
{
/*
* CatchupInterruptHandler). See storage/ipc/sinval[adt].c for the
* use of this.
*/
- if (Shutdown == NoShutdown)
+ if (Shutdown <= SmartShutdown)
SignalChildren(SIGUSR1);
}
* Dummy signal handler
*
* We use this for signals that we don't actually use in the postmaster,
- * but we do use in backends. If we SIG_IGN such signals in the postmaster,
- * then a newly started backend might drop a signal that arrives before it's
- * able to reconfigure its signal processing. (See notes in postgres.c.)
+ * but we do use in backends. If we were to SIG_IGN such signals in the
+ * postmaster, then a newly started backend might drop a signal that arrives
+ * before it's able to reconfigure its signal processing. (See notes in
+ * tcop/postgres.c.)
*/
static void
dummy_handler(SIGNAL_ARGS)
CountChildren(void)
{
Dlelem *curr;
- Backend *bp;
int cnt = 0;
for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr))
{
- bp = (Backend *) DLE_VAL(curr);
- if (bp->pid != MyProcPid)
- cnt++;
- }
- /* Checkpoint and bgwriter will be in the list, discount them */
- if (CheckPointPID != 0)
- cnt--;
- if (BgWriterPID != 0)
- cnt--;
+ cnt++;
+ }
return cnt;
}
/*
- * SSDataBase -- start a non-backend child process for the postmaster
+ * StartChildProcess -- start a non-backend child process for the postmaster
*
* xlog determines what kind of child will be started. All child types
* initially go to BootstrapMain, which will handle common setup.
*
- * Return value of SSDataBase is subprocess' PID, or 0 if failed to start
- * subprocess (0 is returned only for checkpoint/bgwriter cases).
+ * Return value of StartChildProcess is subprocess' PID, or 0 if failed
+ * to start subprocess.
*/
static pid_t
-SSDataBase(int xlop)
+StartChildProcess(int xlop)
{
- Backend *bn;
pid_t pid;
char *av[10];
int ac = 0;
IsUnderPostmaster = true; /* we are a postmaster subprocess now */
/* Close the postmaster's sockets */
- ClosePostmasterPorts(true);
+ ClosePostmasterPorts();
/* Lose the postmaster's on-exit routines and port connections */
on_exit_reset();
ereport(LOG,
(errmsg("could not fork startup process: %m")));
break;
- case BS_XLOG_CHECKPOINT:
- ereport(LOG,
- (errmsg("could not fork checkpoint process: %m")));
- break;
case BS_XLOG_BGWRITER:
ereport(LOG,
- (errmsg("could not fork bgwriter process: %m")));
- break;
- case BS_XLOG_SHUTDOWN:
- ereport(LOG,
- (errmsg("could not fork shutdown process: %m")));
+ (errmsg("could not fork background writer process: %m")));
break;
default:
ereport(LOG,
}
/*
- * fork failure is fatal during startup/shutdown, but there's no
- * need to choke if a routine checkpoint or starting a background
- * writer fails.
+ * fork failure is fatal during startup, but there's no need
+ * to choke immediately if starting other child types fails.
*/
- if (xlop == BS_XLOG_CHECKPOINT)
- return 0;
- if (xlop == BS_XLOG_BGWRITER)
- return 0;
- ExitPostmaster(1);
+ if (xlop == BS_XLOG_STARTUP)
+ ExitPostmaster(1);
+ return 0;
}
/*
* in parent, successful fork
- *
- * The startup and shutdown processes are not considered normal
- * backends, but the checkpoint and bgwriter processes are. They must
- * be added to the list of backends.
*/
- if (xlop == BS_XLOG_CHECKPOINT || xlop == BS_XLOG_BGWRITER)
- {
- if (!(bn = (Backend *) malloc(sizeof(Backend))))
- {
- ereport(LOG,
- (errcode(ERRCODE_OUT_OF_MEMORY),
- errmsg("out of memory")));
- ExitPostmaster(1);
- }
-
- bn->pid = pid;
- bn->cancel_key = PostmasterRandom();
-#ifdef EXEC_BACKEND
- ShmemBackendArrayAdd(bn);
-#endif
- DLAddHead(BackendList, DLNewElem(bn));
-
- /*
- * Since this code is executed periodically, it's a fine place to
- * do other actions that should happen every now and then on no
- * particular schedule. Such as...
- */
- TouchSocketFile();
- TouchSocketLockFile();
- }
-
return pid;
}
#define write_var(var,fp) fwrite((void*)&(var),sizeof(var),1,fp)
#define read_var(var,fp) fread((void*)&(var),sizeof(var),1,fp)
+#define write_array_var(var,fp) fwrite((void*)(var),sizeof(var),1,fp)
+#define read_array_var(var,fp) fread((void*)(var),sizeof(var),1,fp)
static bool
write_backend_variables(char *filename, Port *port)
/* Calculate name for temp file in caller's buffer */
Assert(DataDir);
- snprintf(filename, MAXPGPATH, "%s/%s/%s.backend_var.%lu",
+ snprintf(filename, MAXPGPATH, "%s/%s/%s.backend_var.%d.%lu",
DataDir, PG_TEMP_FILES_DIR, PG_TEMP_FILE_PREFIX,
- ++tmpBackendFileNum);
+ MyProcPid, ++tmpBackendFileNum);
/* Open file */
fp = AllocateFile(filename, PG_BINARY_W);
*/
StrNCpy(str_buf, DataDir, MAXPGPATH);
- fwrite((void *) str_buf, MAXPGPATH, 1, fp);
+ write_array_var(str_buf, fp);
+
+ write_array_var(ListenSocket, fp);
write_var(MyCancelKey, fp);
write_var(debug_flag, fp);
write_var(PostmasterPid, fp);
- fwrite((void *) my_exec_path, MAXPGPATH, 1, fp);
+ StrNCpy(str_buf, my_exec_path, MAXPGPATH);
+ write_array_var(str_buf, fp);
- fwrite((void *) ExtraOptions, sizeof(ExtraOptions), 1, fp);
+ write_array_var(ExtraOptions, fp);
StrNCpy(str_buf, setlocale(LC_COLLATE, NULL), MAXPGPATH);
- fwrite((void *) str_buf, MAXPGPATH, 1, fp);
+ write_array_var(str_buf, fp);
StrNCpy(str_buf, setlocale(LC_CTYPE, NULL), MAXPGPATH);
- fwrite((void *) str_buf, MAXPGPATH, 1, fp);
+ write_array_var(str_buf, fp);
/* Release file */
if (FreeFile(fp))
read_var(port->cryptSalt, fp);
read_var(port->md5Salt, fp);
- fread((void *) str_buf, MAXPGPATH, 1, fp);
+ read_array_var(str_buf, fp);
SetDataDir(str_buf);
+ read_array_var(ListenSocket, fp);
+
read_var(MyCancelKey, fp);
read_var(UsedShmemSegID, fp);
read_var(debug_flag, fp);
read_var(PostmasterPid, fp);
- fread((void *) my_exec_path, MAXPGPATH, 1, fp);
+ read_array_var(str_buf, fp);
+ StrNCpy(my_exec_path, str_buf, MAXPGPATH);
- fread((void *) ExtraOptions, sizeof(ExtraOptions), 1, fp);
+ read_array_var(ExtraOptions, fp);
- fread((void *) str_buf, MAXPGPATH, 1, fp);
+ read_array_var(str_buf, fp);
setlocale(LC_COLLATE, str_buf);
- fread((void *) str_buf, MAXPGPATH, 1, fp);
+ read_array_var(str_buf, fp);
setlocale(LC_CTYPE, str_buf);
/* Release file */
size_t size = ShmemBackendArraySize();
ShmemBackendArray = (Backend *) ShmemAlloc(size);
+ /* Mark all slots as empty */
memset(ShmemBackendArray, 0, size);
}
{
int i;
+ /* Find an empty slot */
for (i = 0; i < NUM_BACKENDARRAY_ELEMS; i++)
{
- /* Find an empty slot */
if (ShmemBackendArray[i].pid == 0)
{
ShmemBackendArray[i] = *bn;
}
ereport(FATAL,
- (errmsg_internal("unable to add backend entry")));
+ (errmsg_internal("no free slots in shmem backend array")));
}
static void
}
/*
- * Note: The following three functions must not be interrupted (eg. by signals).
- * As the Postgres Win32 signalling architecture (currently) requires polling,
- * or APC checking functions which aren't used here, this is not an issue.
+ * Note: The following three functions must not be interrupted (eg. by
+ * signals). As the Postgres Win32 signalling architecture (currently)
+ * requires polling, or APC checking functions which aren't used here, this
+ * is not an issue.
*
- * We keep two separate arrays, instead of a single array of pid/HANDLE structs,
- * to avoid having to re-create a handle array for WaitForMultipleObjects on
- * each call to win32_waitpid.
+ * We keep two separate arrays, instead of a single array of pid/HANDLE
+ * structs, to avoid having to re-create a handle array for
+ * WaitForMultipleObjects on each call to win32_waitpid.
*/
static void
*/
int index;
DWORD exitCode;
- DWORD ret = WaitForMultipleObjects(win32_numChildren, win32_childHNDArray, FALSE, 0);
+ DWORD ret;
+ ret = WaitForMultipleObjects(win32_numChildren, win32_childHNDArray,
+ FALSE, 0);
switch (ret)
{
case WAIT_FAILED:
- ereport(ERROR,
- (errmsg_internal("failed to wait on %lu children: %i",
+ ereport(LOG,
+ (errmsg_internal("failed to wait on %lu children: %d",
win32_numChildren, (int) GetLastError())));
- /* Fall through to WAIT_TIMEOUTs return */
+ return -1;
case WAIT_TIMEOUT:
/* No children have finished */
index = ret - WAIT_OBJECT_0;
Assert(index >= 0 && index < win32_numChildren);
if (!GetExitCodeProcess(win32_childHNDArray[index], &exitCode))
-
+ {
/*
* If we get this far, this should never happen, but,
* then again... No choice other than to assume a
ereport(FATAL,
(errmsg_internal("failed to get exit code for child %lu",
win32_childPIDArray[index])));
+ }
*exitstatus = (int) exitCode;
return win32_childPIDArray[index];
}
return -1;
}
-/* Note! Code belows executes on separate threads, one for
- each child process created */
+/*
+ * Note! Code below executes on separate threads, one for
+ * each child process created
+ */
static DWORD WINAPI
win32_sigchld_waiter(LPVOID param)
{
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.165 2004/05/08 19:09:25 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.166 2004/05/29 22:48:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
bool ShowPinTrace = false;
#endif
-int BgWriterDelay = 200;
-int BgWriterPercent = 1;
-int BgWriterMaxpages = 100;
-
long NDirectFileRead; /* some I/O's are direct file access.
* bypass bufmgr */
long NDirectFileWrite; /* e.g., I/O in psort and hashjoin. */
}
-/*
- * BufferBackgroundWriter
- *
- * Periodically flushes dirty blocks from the buffer pool to keep
- * the LRU list clean, preventing regular backends from writing.
- */
-void
-BufferBackgroundWriter(void)
-{
- if (BgWriterPercent == 0)
- return;
-
- /*
- * Loop forever
- */
- for (;;)
- {
- int n;
- long udelay;
-
- /*
- * Call BufferSync() with instructions to keep just the
- * LRU heads clean.
- */
- n = BufferSync(BgWriterPercent, BgWriterMaxpages);
-
- /*
- * Whatever signal is sent to us, let's just die gallantly. If
- * it wasn't meant that way, the postmaster will reincarnate us.
- */
- if (InterruptPending)
- return;
-
- /*
- * Whenever we have nothing to do, close all smgr files. This
- * is so we won't hang onto smgr references to deleted files
- * indefinitely. XXX this is a bogus, temporary solution. 'Twould
- * be much better to do this once per checkpoint, but the bgwriter
- * doesn't yet know anything about checkpoints.
- */
- if (n == 0)
- smgrcloseall();
-
- /*
- * Nap for the configured time or sleep for 10 seconds if
- * there was nothing to do at all.
- *
- * On some platforms, signals won't interrupt the sleep. To ensure
- * we respond reasonably promptly when the postmaster signals us,
- * break down the sleep into 1-second increments, and check for
- * interrupts after each nap.
- */
- udelay = ((n > 0) ? BgWriterDelay : 10000) * 1000L;
- while (udelay > 1000000L)
- {
- pg_usleep(1000000L);
- udelay -= 1000000L;
- if (InterruptPending)
- return;
- }
- pg_usleep(udelay);
- if (InterruptPending)
- return;
- }
-}
-
/*
* Do whatever is needed to prepare for commit at the bufmgr and smgr levels
*/
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.67 2004/05/28 05:13:03 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.68 2004/05/29 22:48:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "miscadmin.h"
#include "access/clog.h"
#include "access/xlog.h"
+#include "postmaster/bgwriter.h"
#include "storage/bufmgr.h"
#include "storage/freespace.h"
#include "storage/ipc.h"
size += LWLockShmemSize();
size += SInvalShmemSize(maxBackends);
size += FreeSpaceShmemSize();
+ size += BgWriterShmemSize();
#ifdef EXEC_BACKEND
size += ShmemBackendArraySize();
#endif
InitFreeSpaceMap();
/*
- * Set up child-to-postmaster signaling mechanism
+ * Set up interprocess signaling mechanisms
*/
PMSignalInit();
+ BgWriterShmemInit();
#ifdef EXEC_BACKEND
/*
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/ipc/pmsignal.c,v 1.13 2004/02/08 22:28:56 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/ipc/pmsignal.c,v 1.14 2004/05/29 22:48:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
}
return false;
}
+
+/*
+ * PostmasterIsAlive - check whether postmaster process is still alive
+ *
+ * amDirectChild should be passed as "true" by code that knows it is
+ * executing in a direct child process of the postmaster; pass "false"
+ * if an indirect child or not sure. The "true" case uses a faster and
+ * more reliable test, so use it when possible.
+ */
+bool
+PostmasterIsAlive(bool amDirectChild)
+{
+#ifndef WIN32
+ if (amDirectChild)
+ {
+ /*
+ * If the postmaster is alive, we'll still be its child. If it's
+ * died, we'll be reassigned as a child of the init process.
+ */
+ return (getppid() == PostmasterPid);
+ }
+ else
+ {
+ /*
+ * Use kill() to see if the postmaster is still alive. This can
+ * sometimes give a false positive result, since the postmaster's PID
+ * may get recycled, but it is good enough for existing uses by
+ * indirect children.
+ */
+ return (kill(PostmasterPid, 0) == 0);
+ }
+#else /* WIN32 */
+ /*
+ * XXX needs to be implemented by somebody
+ */
+ return true;
+#endif /* WIN32 */
+}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.147 2004/02/18 16:25:12 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.148 2004/05/29 22:48:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
NON_EXEC_STATIC slock_t *ProcStructLock = NULL;
+/* Pointers to shared-memory structures */
static PROC_HDR *ProcGlobal = NULL;
-
-static PGPROC *DummyProc = NULL;
-static int dummy_proc_type = -1;
+static PGPROC *DummyProcs = NULL;
static bool waitingForLock = false;
static bool waitingForSignal = false;
/*
* Create or attach to the PGPROC structures for dummy (checkpoint)
- * processes, too. This does not get linked into the freeProcs
- * list.
+ * processes, too. These do not get linked into the freeProcs list.
*/
- DummyProc = (PGPROC *)
- ShmemInitStruct("DummyProc",sizeof(PGPROC) * NUM_DUMMY_PROCS, &foundDummy);
+ DummyProcs = (PGPROC *)
+ ShmemInitStruct("DummyProcs", sizeof(PGPROC) * NUM_DUMMY_PROCS,
+ &foundDummy);
if (foundProcGlobal || foundDummy)
{
/* both should be present or neither */
Assert(foundProcGlobal && foundDummy);
- return;
}
else
{
ProcGlobal->freeProcs = MAKE_OFFSET(proc);
}
- MemSet(DummyProc, 0, sizeof(PGPROC) * NUM_DUMMY_PROCS);
+ MemSet(DummyProcs, 0, sizeof(PGPROC) * NUM_DUMMY_PROCS);
for (i = 0; i < NUM_DUMMY_PROCS; i++)
{
- DummyProc[i].pid = 0; /* marks DummyProc as not in use */
- PGSemaphoreCreate(&(DummyProc[i].sem));
+ DummyProcs[i].pid = 0; /* marks dummy proc as not in use */
+ PGSemaphoreCreate(&(DummyProcs[i].sem));
}
/* Create ProcStructLock spinlock, too */
MyProc->waitHolder = NULL;
SHMQueueInit(&(MyProc->procHolders));
-
/*
* Arrange to clean up at backend exit.
*/
* This is called by checkpoint processes so that they will have a MyProc
* value that's real enough to let them wait for LWLocks. The PGPROC and
* sema that are assigned are the extra ones created during InitProcGlobal.
+ *
+ * Dummy processes are presently not expected to wait for real (lockmgr)
+ * locks, nor to participate in sinval messaging.
*/
void
InitDummyProcess(int proctype)
* ProcGlobal should be set by a previous call to InitProcGlobal (we
* inherit this by fork() from the postmaster).
*/
- if (ProcGlobal == NULL || DummyProc == NULL)
+ if (ProcGlobal == NULL || DummyProcs == NULL)
elog(PANIC, "proc header uninitialized");
if (MyProc != NULL)
elog(ERROR, "you already exist");
- Assert(dummy_proc_type < 0);
- dummy_proc_type = proctype;
- dummyproc = &DummyProc[proctype];
+ Assert(proctype >= 0 && proctype < NUM_DUMMY_PROCS);
+
+ dummyproc = &DummyProcs[proctype];
/*
* dummyproc should not presently be in use by anyone else
*/
if (dummyproc->pid != 0)
elog(FATAL, "DummyProc[%d] is in use by PID %d",
- proctype, dummyproc->pid);
+ proctype, dummyproc->pid);
MyProc = dummyproc;
/*
* Initialize all fields of MyProc, except MyProc->sem which was set
* up by InitProcGlobal.
*/
- MyProc->pid = MyProcPid; /* marks DummyProc as in use by me */
+ MyProc->pid = MyProcPid; /* marks dummy proc as in use by me */
SHMQueueElemInit(&(MyProc->links));
MyProc->errType = STATUS_OK;
MyProc->xid = InvalidTransactionId;
/*
* Arrange to clean up at process exit.
*/
- on_shmem_exit(DummyProcKill, proctype);
+ on_shmem_exit(DummyProcKill, Int32GetDatum(proctype));
/*
* We might be reusing a semaphore that belonged to a failed process.
static void
DummyProcKill(int code, Datum arg)
{
+ int proctype = DatumGetInt32(arg);
PGPROC *dummyproc;
- Assert(dummy_proc_type >= 0 && dummy_proc_type < NUM_DUMMY_PROCS);
+ Assert(proctype >= 0 && proctype < NUM_DUMMY_PROCS);
- dummyproc = &DummyProc[dummy_proc_type];
+ dummyproc = &DummyProcs[proctype];
- Assert(MyProc != NULL && MyProc == dummyproc);
+ Assert(MyProc == dummyproc);
/* Release any LW locks I am holding */
LWLockReleaseAll();
/* I can't be on regular lock queues, so needn't check */
- /* Mark DummyProc no longer in use */
+ /* Mark dummy proc no longer in use */
MyProc->pid = 0;
/* PGPROC struct isn't mine anymore */
MyProc = NULL;
-
- dummy_proc_type = -1;
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.416 2004/05/28 05:13:12 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.417 2004/05/29 22:48:20 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
* will reread the configuration file. (Better than doing the
* reading in the signal handler, ey?)
*/
-static volatile bool got_SIGHUP = false;
+static volatile sig_atomic_t got_SIGHUP = false;
/*
* Flag to keep track of whether we have started a transaction.
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.217 2004/05/26 13:56:54 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.218 2004/05/29 22:48:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "nodes/makefuncs.h"
#include "parser/parse_expr.h"
#include "parser/parse_type.h"
+#include "postmaster/bgwriter.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteRemove.h"
#include "storage/fd.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
-#include "access/xlog.h"
+
/*
* Error-checking support for DROP commands
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to do CHECKPOINT")));
- CreateCheckPoint(false, false);
+ RequestCheckpoint(true);
break;
case T_ReindexStmt:
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.138 2004/05/28 03:11:15 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/error/elog.c,v 1.139 2004/05/29 22:48:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "pgtime.h"
+#include "postmaster/postmaster.h"
#include "storage/ipc.h"
#include "tcop/tcopprot.h"
#include "utils/memutils.h"
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/init/globals.c,v 1.88 2004/05/28 05:13:15 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/init/globals.c,v 1.89 2004/05/29 22:48:21 tgl Exp $
*
* NOTES
* Globals used all over the place should be declared here and not
bool allowSystemTableMods = false;
int work_mem = 1024;
int maintenance_work_mem = 16384;
+
+/* Primary determinants of sizes of shared-memory structures: */
int NBuffers = 1000;
+int MaxBackends = 100;
int VacuumCostPageHit = 1; /* GUC parameters for vacuum */
int VacuumCostPageMiss = 10;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.132 2004/05/27 17:12:54 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.133 2004/05/29 22:48:21 tgl Exp $
*
*
*-------------------------------------------------------------------------
#include "commands/trigger.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
+#include "postmaster/postmaster.h"
#include "storage/backendid.h"
#include "storage/ipc.h"
#include "storage/proc.h"
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.208 2004/05/26 15:07:39 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.209 2004/05/29 22:48:21 tgl Exp $
*
*--------------------------------------------------------------------
*/
#include "optimizer/prep.h"
#include "parser/parse_expr.h"
#include "parser/parse_relation.h"
+#include "postmaster/bgwriter.h"
+#include "postmaster/postmaster.h"
#include "storage/bufmgr.h"
#include "storage/fd.h"
#include "storage/freespace.h"
#endif
/* XXX these should appear in other modules' header files */
-extern bool Log_connections;
extern bool Log_disconnections;
extern DLLIMPORT bool check_function_bodies;
-extern int PreAuthDelay;
-extern int AuthenticationTimeout;
-extern int CheckPointTimeout;
extern int CommitDelay;
extern int CommitSiblings;
-extern char *preload_libraries_string;
extern int DebugSharedBuffers;
static const char *assign_log_destination(const char *value,
NULL
},
&BgWriterPercent,
- 1, 0, 100, NULL, NULL
+ 1, 1, 100, NULL, NULL
},
{
gettext_noop("Background writer maximum number of pages to flush per round"),
NULL
},
- &BgWriterMaxpages,
+ &BgWriterMaxPages,
100, 1, 1000, NULL, NULL
},
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/access/xlog.h,v 1.50 2004/05/27 17:12:57 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/access/xlog.h,v 1.51 2004/05/29 22:48:22 tgl Exp $
*/
#ifndef XLOG_H
#define XLOG_H
/* these variables are GUC parameters related to XLOG */
extern int CheckPointSegments;
-extern int CheckPointWarning;
extern int XLOGbuffers;
extern char *XLOG_sync_method;
extern const char XLOG_sync_method_default[];
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/bootstrap/bootstrap.h,v 1.34 2004/05/28 05:13:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/bootstrap/bootstrap.h,v 1.35 2004/05/29 22:48:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#define BS_XLOG_NOP 0
#define BS_XLOG_BOOTSTRAP 1
#define BS_XLOG_STARTUP 2
-#define BS_XLOG_CHECKPOINT 3
-#define BS_XLOG_BGWRITER 4
-#define BS_XLOG_SHUTDOWN 5
+#define BS_XLOG_BGWRITER 3
#endif /* BOOTSTRAP_H */
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.161 2004/05/28 05:13:24 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.162 2004/05/29 22:48:22 tgl Exp $
*
* NOTES
- * some of the information in this file should be moved to
- * other files.
+ * some of the information in this file should be moved to other files.
*
*-------------------------------------------------------------------------
*/
#define MISCADMIN_H
+#define PG_VERSIONSTR "postgres (PostgreSQL) " PG_VERSION "\n"
+
+
/*****************************************************************************
* System interrupt and critical section handling
*
extern void ProcessInterrupts(void);
#ifndef WIN32
+
#define CHECK_FOR_INTERRUPTS() \
do { \
if (InterruptPending) \
ProcessInterrupts(); \
} while(0)
-#else
+
+#else /* WIN32 */
+
#define CHECK_FOR_INTERRUPTS() \
do { \
if (WaitForSingleObject(pgwin32_signal_event,0) == WAIT_OBJECT_0) \
if (InterruptPending) \
ProcessInterrupts(); \
} while(0)
-#endif
+
+#endif /* WIN32 */
#define HOLD_INTERRUPTS() (InterruptHoldoffCount++)
* globals.h -- *
*****************************************************************************/
-/*
- * from postmaster/postmaster.c
- */
-extern bool ClientAuthInProgress;
-
-extern int PostmasterMain(int argc, char *argv[]);
-extern void ClosePostmasterPorts(bool pgstat_too);
-#ifdef EXEC_BACKEND
-extern pid_t postmaster_forkexec(int argc, char *argv[]);
-extern int SubPostmasterMain(int argc, char *argv[]);
-#endif
-
-#define PG_VERSIONSTR "postgres (PostgreSQL) " PG_VERSION "\n"
-
/*
* from utils/init/globals.c
*/
extern char *DataDir;
+extern DLLIMPORT int NBuffers;
+extern int MaxBackends;
+
extern DLLIMPORT int MyProcPid;
extern struct Port *MyProcPort;
extern long MyCancelKey;
extern int VacuumCostBalance;
extern bool VacuumCostActive;
-/*
- * A few postmaster startup options are exported here so the
- * configuration file processor can access them.
- */
-extern bool EnableSSL;
-extern bool SilentMode;
-extern int MaxBackends;
-extern int ReservedBackends;
-extern DLLIMPORT int NBuffers;
-extern int PostPortNumber;
-extern int Unix_socket_permissions;
-extern char *Unix_socket_group;
-extern char *UnixSocketDir;
-extern char *ListenAddresses;
-
/* in tcop/postgres.c */
extern void check_stack_depth(void);
*
* Copyright (c) 2001-2003, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/include/pgstat.h,v 1.22 2004/05/28 05:13:25 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/pgstat.h,v 1.23 2004/05/29 22:48:22 tgl Exp $
* ----------
*/
#ifndef PGSTAT_H
extern void pgstat_init(void);
extern void pgstat_start(void);
extern bool pgstat_ispgstat(int pid);
-extern void pgstat_close_sockets(void);
extern void pgstat_beterm(int pid);
#ifdef EXEC_BACKEND
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * bgwriter.h
+ * Exports from postmaster/bgwriter.c.
+ *
+ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
+ *
+ * $PostgreSQL: pgsql/src/include/postmaster/bgwriter.h,v 1.1 2004/05/29 22:48:23 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef _BGWRITER_H
+#define _BGWRITER_H
+
+/* GUC options */
+extern int BgWriterDelay;
+extern int BgWriterPercent;
+extern int BgWriterMaxPages;
+extern int CheckPointTimeout;
+extern int CheckPointWarning;
+
+extern void BackgroundWriterMain(void);
+
+extern void RequestCheckpoint(bool waitforit);
+
+extern int BgWriterShmemSize(void);
+extern void BgWriterShmemInit(void);
+
+#endif /* _BGWRITER_H */
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * postmaster.h
+ * Exports from postmaster/postmaster.c.
+ *
+ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $PostgreSQL: pgsql/src/include/postmaster/postmaster.h,v 1.1 2004/05/29 22:48:23 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef _POSTMASTER_H
+#define _POSTMASTER_H
+
+/* GUC options */
+extern bool EnableSSL;
+extern bool SilentMode;
+extern int ReservedBackends;
+extern int PostPortNumber;
+extern int Unix_socket_permissions;
+extern char *Unix_socket_group;
+extern char *UnixSocketDir;
+extern char *ListenAddresses;
+extern bool ClientAuthInProgress;
+extern int PreAuthDelay;
+extern int AuthenticationTimeout;
+extern char *preload_libraries_string;
+extern bool Log_connections;
+extern bool log_hostname;
+extern char *rendezvous_name;
+
+
+extern int PostmasterMain(int argc, char *argv[]);
+extern void ClosePostmasterPorts(void);
+#ifdef EXEC_BACKEND
+extern pid_t postmaster_forkexec(int argc, char *argv[]);
+extern int SubPostmasterMain(int argc, char *argv[]);
+#endif
+
+#endif /* _POSTMASTER_H */
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/storage/bufmgr.h,v 1.79 2004/05/08 19:09:25 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/storage/bufmgr.h,v 1.80 2004/05/29 22:48:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/* in bufmgr.c */
extern bool zero_damaged_pages;
-extern int BgWriterDelay;
-extern int BgWriterPercent;
-extern int BgWriterMaxpages;
-
-
/* in buf_init.c */
extern DLLIMPORT Block *BufferBlockPointers;
extern int32 *PrivateRefCount;
extern void BufmgrCommit(void);
extern int BufferSync(int percent, int maxpages);
-extern void BufferBackgroundWriter(void);
-extern const char *BgWriterAssignSyncMethod(const char *method,
- bool doid, bool interactive);
extern void InitLocalBuffer(void);
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/storage/pmsignal.h,v 1.7 2004/05/23 03:50:45 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/storage/pmsignal.h,v 1.8 2004/05/29 22:48:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
typedef enum
{
- PMSIGNAL_DO_CHECKPOINT, /* request to start a checkpoint */
PMSIGNAL_PASSWORD_CHANGE, /* pg_pwd file has changed */
PMSIGNAL_WAKEN_CHILDREN, /* send a SIGUSR1 signal to all backends */
extern void PMSignalInit(void);
extern void SendPostmasterSignal(PMSignalReason reason);
extern bool CheckPostmasterSignal(PMSignalReason reason);
+extern bool PostmasterIsAlive(bool amDirectChild);
#endif /* PMSIGNAL_H */
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.65 2004/04/11 00:54:45 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.66 2004/05/29 22:48:23 tgl Exp $
*
* OLD COMMENTS
* This file was created so that other c files could get the two
extern bool Warn_restart_ready;
extern bool InError;
extern CommandDest whereToSendOutput;
-extern bool log_hostname;
extern DLLIMPORT const char *debug_query_string;
-extern char *rendezvous_name;
extern int max_stack_depth;
extern bool in_fatal_exit;