]> granicus.if.org Git - postgresql/commitdiff
Separate out bgwriter code into a logically separate module, rather
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 29 May 2004 22:48:23 +0000 (22:48 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 29 May 2004 22:48:23 +0000 (22:48 +0000)
than being random pieces of other files.  Give bgwriter responsibility
for all checkpoint activity (other than a post-recovery checkpoint);
so this child process absorbs the functionality of the former transient
checkpoint and shutdown subprocesses.  While at it, create an actual
include file for postmaster.c, which for some reason never had its own
file before.

28 files changed:
src/backend/access/transam/slru.c
src/backend/access/transam/xlog.c
src/backend/bootstrap/bootstrap.c
src/backend/libpq/pqsignal.c
src/backend/main/main.c
src/backend/postmaster/Makefile
src/backend/postmaster/bgwriter.c [new file with mode: 0644]
src/backend/postmaster/pgstat.c
src/backend/postmaster/postmaster.c
src/backend/storage/buffer/bufmgr.c
src/backend/storage/ipc/ipci.c
src/backend/storage/ipc/pmsignal.c
src/backend/storage/lmgr/proc.c
src/backend/tcop/postgres.c
src/backend/tcop/utility.c
src/backend/utils/error/elog.c
src/backend/utils/init/globals.c
src/backend/utils/init/postinit.c
src/backend/utils/misc/guc.c
src/include/access/xlog.h
src/include/bootstrap/bootstrap.h
src/include/miscadmin.h
src/include/pgstat.h
src/include/postmaster/bgwriter.h [new file with mode: 0644]
src/include/postmaster/postmaster.h [new file with mode: 0644]
src/include/storage/bufmgr.h
src/include/storage/pmsignal.h
src/include/tcop/tcopprot.h

index dff221bf27730e30b3e5bcca871b1e0efae1cbb4..57dcd2b33798c3e9230681bb5cfaee593903aa5a 100644 (file)
@@ -6,7 +6,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,6 +17,7 @@
 #include <unistd.h>
 
 #include "access/slru.h"
+#include "postmaster/bgwriter.h"
 #include "storage/fd.h"
 #include "storage/lwlock.h"
 #include "miscadmin.h"
@@ -795,8 +796,8 @@ SimpleLruTruncate(SlruCtl ctl, int cutoffPage)
        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,
index 348906ea4ac13ea7d326541cda4b41689eb8c8d0..cfb864d09411c096ac735a09a343d885b9a44d54 100644 (file)
@@ -7,7 +7,7 @@
  * 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"
@@ -1206,9 +1206,9 @@ XLogWrite(XLogwrtRqst WriteRqst)
                                {
 #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);
@@ -3087,11 +3087,6 @@ StartupXLOG(void)
                                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
@@ -3293,11 +3288,6 @@ ShutdownXLOG(int code, Datum arg)
        ereport(LOG,
                        (errmsg("shutting down")));
 
-       /* suppress in-transaction check in CreateCheckPoint */
-       MyLastRecPtr.xrecoff = 0;
-       MyXactMadeXLogEntry = false;
-       MyXactMadeTempRelUpdate = false;
-
        CritSectionCount++;
        CreateCheckPoint(true, true);
        ShutdownCLOG();
@@ -3324,27 +3314,13 @@ CreateCheckPoint(bool shutdown, bool force)
        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.
index ed42bf133c7fc97a8016f16092f5d7eef5074b96..a19217a47b2631b1cafc0469ee7fa926ec66f7b1 100644 (file)
@@ -8,7 +8,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -33,6 +33,7 @@
 #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"
@@ -50,6 +51,8 @@
 #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);
@@ -192,44 +195,8 @@ typedef struct _IndexList
 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
@@ -387,19 +354,13 @@ BootstrapMain(int argc, char *argv[])
                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, "", "");
@@ -415,48 +376,9 @@ BootstrapMain(int argc, char *argv[])
                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);
@@ -488,37 +410,30 @@ BootstrapMain(int argc, char *argv[])
        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);
@@ -575,9 +490,90 @@ BootstrapMain(int argc, char *argv[])
 
        /* 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
  * ----------------------------------------------------------------
index dc1f6ccc0871b6a0defb1c3deaef56b51e63d660..468c062aa4330cf041c125ea767cae8cb7fb00a5 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * 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.
  *
@@ -153,4 +164,5 @@ pqsignal(int signo, pqsigfunc func)
        return oact.sa_handler;
 #endif   /* !HAVE_POSIX_SIGNALS */
 }
+
 #endif /* WIN32 */
index 272d4cc0d0a0bad3cbbc73e522d4089219acf774..aee2da0731503398e960c985b2fb179383f30ffa 100644 (file)
@@ -13,7 +13,7 @@
  *
  *
  * 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
index b56881fc86eff6b97d363127c75cce2bdb1a864e..489c6d921123c8e93c84d9a80b0f7509d75897fa 100644 (file)
@@ -1,10 +1,10 @@
 #-------------------------------------------------------------------------
 #
 # 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 $
 #
 #-------------------------------------------------------------------------
 
@@ -12,7 +12,7 @@ subdir = src/backend/postmaster
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
-OBJS = postmaster.o pgstat.o
+OBJS = postmaster.o bgwriter.o pgstat.o
 
 all: SUBSYS.o
 
diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c
new file mode 100644 (file)
index 0000000..ce80a4f
--- /dev/null
@@ -0,0 +1,456 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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);
+               }
+       }
+}
index a3a4e57c85594048e4f3ccd1f1ffe6484a93234f..c90749ca12763f717e3698ca4eb5fb922c3ee979 100644 (file)
@@ -13,7 +13,7 @@
  *
  *     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"
 
 
@@ -75,8 +77,6 @@ bool          pgstat_is_running = false;
 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;
@@ -397,17 +397,6 @@ pgstat_init(void)
                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;
@@ -439,9 +428,9 @@ startup_failed:
 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";
 
@@ -464,11 +453,7 @@ pgstat_forkexec(STATS_PROCESS_TYPE procType)
        /* 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]);
 
@@ -493,14 +478,10 @@ pgstat_forkexec(STATS_PROCESS_TYPE procType)
 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++]);
 }
@@ -592,8 +573,8 @@ pgstat_start(void)
                        /* 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();
@@ -632,31 +613,6 @@ pgstat_ispgstat(int pid)
 }
 
 
-/* ----------
- * 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() -
  *
@@ -1445,15 +1401,6 @@ PgstatBufferMain(int argc, char *argv[])
        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.
@@ -1517,7 +1464,6 @@ PgstatCollectorMain(int argc, char *argv[])
        PgStat_Msg      msg;
        fd_set          rfds;
        int                     readPipe;
-       int                     pmPipe;
        int                     nready;
        int                     len = 0;
        struct timeval timeout;
@@ -1555,7 +1501,6 @@ PgstatCollectorMain(int argc, char *argv[])
        /* Close unwanted files */
        closesocket(pgStatPipe[1]);
        closesocket(pgStatSock);
-       pmPipe = pgStatCollectorPmPipe[0];
 
        /*
         * Identify myself via ps
@@ -1823,17 +1768,9 @@ PgstatCollectorMain(int argc, char *argv[])
         * 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();
 }
 
@@ -1852,8 +1789,8 @@ pgstat_recvbuffer(void)
 {
        fd_set          rfds;
        fd_set          wfds;
+       struct timeval timeout;
        int                     writePipe = pgStatPipe[1];
-       int                     pmPipe = pgStatPmPipe[0];
        int                     maxfd;
        int                     nready;
        int                     len;
@@ -1937,8 +1874,7 @@ pgstat_recvbuffer(void)
 
                /*
                 * 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)
                {
@@ -1946,17 +1882,16 @@ pgstat_recvbuffer(void)
                        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)
@@ -2062,11 +1997,9 @@ pgstat_recvbuffer(void)
                        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);
        }
 }
index 89a22815098955fc0fcc5d5050bac3d087ff26bd..e7186c01b39b5f575189a463e5564bbee7ad4dd0 100644 (file)
  *
  *
  * 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
@@ -97,6 +96,7 @@
 #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
 {
@@ -148,15 +140,6 @@ int                        PostPortNumber;
 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
@@ -196,9 +179,6 @@ bool                SilentMode = false; /* silent mode (-S) */
 
 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;
@@ -209,13 +189,11 @@ char         *rendezvous_name;
 /* 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
@@ -232,7 +210,6 @@ bool                ClientAuthInProgress = false;           /* T during new-client
  * 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;
@@ -263,6 +240,7 @@ static void reaper(SIGNAL_ARGS);
 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);
@@ -280,7 +258,7 @@ static void RandomSalt(char *cryptSalt, char *md5Salt);
 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. */
@@ -311,10 +289,8 @@ static void ShmemBackendArrayRemove(pid_t pid);
 
 #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)
 
 
 /*
@@ -325,14 +301,13 @@ PostmasterMain(int argc, char *argv[])
 {
        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;
 
        /*
@@ -359,8 +334,6 @@ PostmasterMain(int argc, char *argv[])
         */
        umask((mode_t) 0077);
 
-       MyProcPid = PostmasterPid = getpid();
-
        /*
         * Fire up essential subsystems: memory management
         */
@@ -470,12 +443,10 @@ PostmasterMain(int argc, char *argv[])
                        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);
@@ -656,7 +627,7 @@ PostmasterMain(int argc, char *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);
@@ -766,12 +737,13 @@ PostmasterMain(int argc, char *argv[])
        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),
@@ -791,16 +763,16 @@ PostmasterMain(int argc, char *argv[])
         *
         * CAUTION: when changing this list, check for side-effects on the signal
         * handling setup of child processes.  See tcop/postgres.c,
-        * bootstrap/bootstrap.c, 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 */
@@ -822,19 +794,6 @@ PostmasterMain(int argc, char *argv[])
         */
        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
         */
@@ -956,10 +915,7 @@ reg_reply(DNSServiceRegistrationReplyErrorType errorCode, void *context)
 static void
 pmdaemonize(void)
 {
-#ifdef WIN32
-       /* not supported */
-       elog(FATAL, "SilentMode not supported under WIN32");
-#else
+#ifndef WIN32
        int                     i;
        pid_t           pid;
 
@@ -989,7 +945,7 @@ pmdaemonize(void)
        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.
@@ -1007,7 +963,10 @@ pmdaemonize(void)
        dup2(i, 1);
        dup2(i, 2);
        close(i);
-#endif
+#else  /* WIN32 */
+       /* not supported */
+       elog(FATAL, "SilentMode not supported under WIN32");
+#endif /* WIN32 */
 }
 
 
@@ -1053,19 +1012,21 @@ usage(const char *progname)
 
 
 /*
- * 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);
 
@@ -1074,70 +1035,32 @@ ServerLoop(void)
                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,
@@ -1147,63 +1070,85 @@ ServerLoop(void)
                }
 
                /*
-                * 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)
@@ -1543,14 +1488,7 @@ processCancelRequest(Port *port, void *pkt)
        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",
@@ -1561,7 +1499,7 @@ processCancelRequest(Port *port, void *pkt)
        /*
         * 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))
@@ -1687,7 +1625,7 @@ ConnFree(Port *conn)
  * them open, of course.
  */
 void
-ClosePostmasterPorts(bool pgstat_too)
+ClosePostmasterPorts(void)
 {
        int                     i;
 
@@ -1700,10 +1638,6 @@ ClosePostmasterPorts(bool pgstat_too)
                        ListenSocket[i] = -1;
                }
        }
-
-       /* Close pgstat control sockets, unless we're starting pgstat itself */
-       if (pgstat_too)
-               pgstat_close_sockets();
 }
 
 
@@ -1741,6 +1675,8 @@ SIGHUP_handler(SIGNAL_ARGS)
                         (errmsg("received SIGHUP, reloading configuration files")));
                ProcessConfigFile(PGC_SIGHUP);
                SignalChildren(SIGHUP);
+               if (BgWriterPID != 0)
+                       kill(BgWriterPID, SIGHUP);
                load_hba();
                load_ident();
 
@@ -1748,13 +1684,6 @@ SIGHUP_handler(SIGNAL_ARGS)
                /* 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);
@@ -1780,11 +1709,10 @@ pmdie(SIGNAL_ARGS)
        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;
@@ -1792,36 +1720,28 @@ pmdie(SIGNAL_ARGS)
                        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;
@@ -1842,33 +1762,34 @@ pmdie(SIGNAL_ARGS)
                        }
 
                        /*
-                        * 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);
@@ -1939,22 +1860,11 @@ reaper(SIGNAL_ARGS)
                }
 
                /*
-                * 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"),
@@ -1963,7 +1873,6 @@ reaper(SIGNAL_ARGS)
                                                (errmsg("aborting startup due to startup process failure")));
                                ExitPostmaster(1);
                        }
-                       StartupPID = 0;
 
                        /*
                         * Startup succeeded - we are done with system startup or recovery.
@@ -1971,33 +1880,51 @@ reaper(SIGNAL_ARGS)
                        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)
@@ -2006,7 +1933,7 @@ reaper(SIGNAL_ARGS)
                 * 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")));
@@ -2021,11 +1948,14 @@ reaper(SIGNAL_ARGS)
 
        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:
@@ -2044,11 +1974,9 @@ static void
 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
@@ -2056,61 +1984,81 @@ CleanupProc(int pid,
         * 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,
@@ -2130,34 +2078,18 @@ CleanupProc(int pid,
                                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;
@@ -2204,26 +2136,16 @@ LogChildExit(int lev, const char *procname, int pid, int exitstatus)
 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);
        }
 }
 
@@ -2346,10 +2268,10 @@ BackendStartup(Port *port)
         */
        bn->pid = pid;
        bn->cancel_key = MyCancelKey;
+       DLAddHead(BackendList, DLNewElem(bn));
 #ifdef EXEC_BACKEND
        ShmemBackendArrayAdd(bn);
 #endif
-       DLAddHead(BackendList, DLNewElem(bn));
 
        return STATUS_OK;
 }
@@ -2438,9 +2360,9 @@ BackendRun(Port *port)
 
        /*
         * 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();
@@ -2833,23 +2755,23 @@ SubPostmasterMain(int argc, char *argv[])
        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)
        {
@@ -2861,7 +2783,7 @@ SubPostmasterMain(int argc, char *argv[])
                /* Do not want to attach to shared memory */
 
                PgstatCollectorMain(argc, argv);
-               ExitPostmaster(0);
+               proc_exit(0);
        }
 
        return 1;                                       /* shouldn't get here */
@@ -2886,8 +2808,6 @@ ExitPostmaster(int status)
         *
         * MUST         -- vadim 05-10-1999
         */
-       /* Should I use true instead? */
-       ClosePostmasterPorts(false);
 
        proc_exit(status);
 }
@@ -2902,45 +2822,6 @@ sigusr1_handler(SIGNAL_ARGS)
 
        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))
        {
                /*
@@ -2957,7 +2838,7 @@ sigusr1_handler(SIGNAL_ARGS)
                 * CatchupInterruptHandler). See storage/ipc/sinval[adt].c for the
                 * use of this.
                 */
-               if (Shutdown == NoShutdown)
+               if (Shutdown <= SmartShutdown)
                        SignalChildren(SIGUSR1);
        }
 
@@ -2971,9 +2852,10 @@ sigusr1_handler(SIGNAL_ARGS)
  * 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)
@@ -3057,37 +2939,28 @@ static int
 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;
@@ -3153,7 +3026,7 @@ SSDataBase(int xlop)
                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();
@@ -3180,17 +3053,9 @@ SSDataBase(int xlop)
                                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,
@@ -3199,50 +3064,17 @@ SSDataBase(int xlop)
                }
 
                /*
-                * 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;
 }
 
@@ -3316,6 +3148,8 @@ extern int        pgStatSock;
 
 #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)
@@ -3326,9 +3160,9 @@ 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);
@@ -3366,7 +3200,9 @@ write_backend_variables(char *filename, Port *port)
         */
 
        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);
 
@@ -3386,14 +3222,15 @@ write_backend_variables(char *filename, Port *port)
        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))
@@ -3430,9 +3267,11 @@ read_backend_variables(char *filename, Port *port)
        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);
@@ -3451,13 +3290,14 @@ read_backend_variables(char *filename, Port *port)
        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 */
@@ -3481,6 +3321,7 @@ ShmemBackendArrayAllocation(void)
        size_t          size = ShmemBackendArraySize();
 
        ShmemBackendArray = (Backend *) ShmemAlloc(size);
+       /* Mark all slots as empty */
        memset(ShmemBackendArray, 0, size);
 }
 
@@ -3489,9 +3330,9 @@ ShmemBackendArrayAdd(Backend *bn)
 {
        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;
@@ -3500,7 +3341,7 @@ ShmemBackendArrayAdd(Backend *bn)
        }
 
        ereport(FATAL,
-                       (errmsg_internal("unable to add backend entry")));
+                       (errmsg_internal("no free slots in shmem backend array")));
 }
 
 static void
@@ -3597,13 +3438,14 @@ win32_forkexec(const char *path, char *argv[])
 }
 
 /*
- * 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
@@ -3662,15 +3504,17 @@ win32_waitpid(int *exitstatus)
                 */
                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 */
@@ -3685,7 +3529,7 @@ win32_waitpid(int *exitstatus)
                                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
@@ -3694,6 +3538,7 @@ win32_waitpid(int *exitstatus)
                                        ereport(FATAL,
                                                        (errmsg_internal("failed to get exit code for child %lu",
                                                                                   win32_childPIDArray[index])));
+                               }
                                *exitstatus = (int) exitCode;
                                return win32_childPIDArray[index];
                }
@@ -3703,8 +3548,10 @@ win32_waitpid(int *exitstatus)
        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)
 {
index 4f6772564a8df76148624befcdb5997c7a723138..f718e33cd598beddb09c76f8467e18f16017c162 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -60,10 +60,6 @@ bool         zero_damaged_pages = false;
 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. */
@@ -862,72 +858,6 @@ FlushBufferPool(void)
 }
 
 
-/*
- * 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
  */
index 4ce5c98b577bf9cb21b14f2aea186388eb7c6aeb..69c460306b4199d51647abd2d3f409b95f2efd24 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,6 +18,7 @@
 #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"
@@ -72,6 +73,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate,
                size += LWLockShmemSize();
                size += SInvalShmemSize(maxBackends);
                size += FreeSpaceShmemSize();
+               size += BgWriterShmemSize();
 #ifdef EXEC_BACKEND
                size += ShmemBackendArraySize();
 #endif
@@ -155,9 +157,10 @@ CreateSharedMemoryAndSemaphores(bool makePrivate,
        InitFreeSpaceMap();
 
        /*
-        * Set up child-to-postmaster signaling mechanism
+        * Set up interprocess signaling mechanisms
         */
        PMSignalInit();
+       BgWriterShmemInit();
 
 #ifdef EXEC_BACKEND
        /*
index b0fc1aea0ff2a847592bf3c5601ff7f1e7ff5dcf..4efa4adac6f80ec6d474eac77e924208f1028a75 100644 (file)
@@ -8,7 +8,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -83,3 +83,41 @@ CheckPostmasterSignal(PMSignalReason reason)
        }
        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 */
+}
index 19ce44ff687f46e47adeece77b60763c7fa4db45..dbf5b414153f01238234c0bbfba1e6e7947c01b2 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -68,10 +68,9 @@ PGPROC          *MyProc = NULL;
  */
 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;
@@ -130,17 +129,16 @@ InitProcGlobal(int maxBackends)
 
        /*
         * 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
        {
@@ -170,11 +168,11 @@ InitProcGlobal(int maxBackends)
                        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 */
@@ -249,7 +247,6 @@ InitProcess(void)
        MyProc->waitHolder = NULL;
        SHMQueueInit(&(MyProc->procHolders));
 
-
        /*
         * Arrange to clean up at backend exit.
         */
@@ -274,6 +271,9 @@ InitProcess(void)
  * 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)
@@ -284,29 +284,29 @@ 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;
@@ -323,7 +323,7 @@ InitDummyProcess(int proctype)
        /*
         * 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.
@@ -459,13 +459,14 @@ ProcKill(int code, Datum arg)
 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();
@@ -477,13 +478,11 @@ DummyProcKill(int code, Datum arg)
 
        /* 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;
 }
 
 
index 7acaf9117db22ff8921d29bd7872d46d93a55b45..556528d6d2d1fda6e2ba77bf01eb18f6c77c64e6 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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
@@ -110,7 +110,7 @@ static char *stack_base_ptr = NULL;
  * 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.
index 39b69c6248c2e6fb34eacaf49c9e8da99a22d37d..4d6c246cea1a8ba483f14670889e1abc881d834b 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -45,6 +45,7 @@
 #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"
@@ -54,7 +55,7 @@
 #include "utils/guc.h"
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
-#include "access/xlog.h"
+
 
 /*
  * Error-checking support for DROP commands
@@ -892,7 +893,7 @@ ProcessUtility(Node *parsetree,
                                ereport(ERROR,
                                                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                                 errmsg("must be superuser to do CHECKPOINT")));
-                       CreateCheckPoint(false, false);
+                       RequestCheckpoint(true);
                        break;
 
                case T_ReindexStmt:
index b76c4cb88b0941df0d3f66c7248c32e8464db0e4..e3adab82979d3f50aac2c5406d9702eda8b2a407 100644 (file)
@@ -37,7 +37,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -57,6 +57,7 @@
 #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"
index 85c3e23a019a9e2f1638f5454d97d891f3879ab5..2a22f666f6d29953e23e07d747c978e1a074024c 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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
@@ -85,7 +85,10 @@ bool         enableFsync = true;
 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;
index 69d4d974099d0b8794af15f3c6f63ab7038be85c..e80187d57523403ad6ae1bd424f173f58e14d15a 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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 $
  *
  *
  *-------------------------------------------------------------------------
@@ -29,6 +29,7 @@
 #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"
index 1620a8607c28c8e351ece360c3a8de19064b9bed..eda37c1be2c46c39010b4ed03cc0bc4cac8bac60 100644 (file)
@@ -10,7 +10,7 @@
  * 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 $
  *
  *--------------------------------------------------------------------
  */
@@ -44,6 +44,8 @@
 #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,
@@ -1262,7 +1259,7 @@ static struct config_int ConfigureNamesInt[] =
                        NULL
                },
                &BgWriterPercent,
-               1, 0, 100, NULL, NULL
+               1, 1, 100, NULL, NULL
        },
 
        {
@@ -1270,7 +1267,7 @@ static struct config_int ConfigureNamesInt[] =
                        gettext_noop("Background writer maximum number of pages to flush per round"),
                        NULL
                },
-               &BgWriterMaxpages,
+               &BgWriterMaxPages,
                100, 1, 1000, NULL, NULL
        },
 
index b0ebedcf329939b91825d399b1a3ab2ddbb576be..0e44e77446d650f98243117fbf26041903c1a378 100644 (file)
@@ -6,7 +6,7 @@
  * 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
@@ -207,7 +207,6 @@ extern XLogRecPtr ProcLastRecEnd;
 
 /* 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[];
index 7dd9c808fded8c933bf587b2f3dd32fe950f2c4e..21ed48286927ff3470fd93e72000f8ef955f249b 100644 (file)
@@ -7,7 +7,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -58,8 +58,6 @@ extern void Int_yyerror(const char *str);
 #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 */
index e8e35fd6b58c24db5e060724eac34b8958fd9a9e..4561d2fcfb76a9f15ac145659e091f8e3218cbe2 100644 (file)
  * 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.
  *
  *-------------------------------------------------------------------------
  */
@@ -25,6 +24,9 @@
 #define MISCADMIN_H
 
 
+#define PG_VERSIONSTR "postgres (PostgreSQL) " PG_VERSION "\n"
+
+
 /*****************************************************************************
  *       System interrupt and critical section handling
  *
@@ -75,12 +77,15 @@ extern volatile uint32 CritSectionCount;
 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) \
@@ -88,7 +93,8 @@ do { \
        if (InterruptPending) \
                ProcessInterrupts(); \
 } while(0)
-#endif
+
+#endif /* WIN32 */
 
 
 #define HOLD_INTERRUPTS()  (InterruptHoldoffCount++)
@@ -112,20 +118,6 @@ do { \
  *       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
  */
@@ -137,6 +129,9 @@ extern bool ExitOnAnyError;
 
 extern char *DataDir;
 
+extern DLLIMPORT int NBuffers;
+extern int     MaxBackends;
+
 extern DLLIMPORT int MyProcPid;
 extern struct Port *MyProcPort;
 extern long MyCancelKey;
@@ -216,21 +211,6 @@ extern int VacuumCostNaptime;
 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);
index 8f7c4dc4515b7aaa1905f749d274b761f74de5d4..96d3af7ab051978f6ab4c957e3a1b8d049402e02 100644 (file)
@@ -5,7 +5,7 @@
  *
  *     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
@@ -349,7 +349,6 @@ extern bool pgstat_is_running;
 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
diff --git a/src/include/postmaster/bgwriter.h b/src/include/postmaster/bgwriter.h
new file mode 100644 (file)
index 0000000..c11af72
--- /dev/null
@@ -0,0 +1,29 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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 */
diff --git a/src/include/postmaster/postmaster.h b/src/include/postmaster/postmaster.h
new file mode 100644 (file)
index 0000000..d349018
--- /dev/null
@@ -0,0 +1,41 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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 */
index 0aab9ad24f4466d39e3a2354cae535d0d031ad73..27752d412b56435ddbe61bf77adcd83554d1df92 100644 (file)
@@ -7,7 +7,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -28,11 +28,6 @@ extern DLLIMPORT int NBuffers;
 /* 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;
@@ -179,9 +174,6 @@ extern void AbortBufferIO(void);
 
 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);
 
index 688b83adab17bec45cc2013ecaf07e5695d96fc1..4180c95c735654e97c98d2ddb0c35ca27297349c 100644 (file)
@@ -7,7 +7,7 @@
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,7 +22,6 @@
  */
 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 */
 
@@ -35,5 +34,6 @@ typedef enum
 extern void PMSignalInit(void);
 extern void SendPostmasterSignal(PMSignalReason reason);
 extern bool CheckPostmasterSignal(PMSignalReason reason);
+extern bool PostmasterIsAlive(bool amDirectChild);
 
 #endif   /* PMSIGNAL_H */
index 97556ccbf1de1fb1a4df065c643d0c3e810f5c8e..1218e04fdfbc821077aca83d1ec1fd2260d0d91b 100644 (file)
@@ -7,7 +7,7 @@
  * 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
@@ -30,9 +30,7 @@ extern DLLIMPORT sigjmp_buf Warn_restart;
 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;