diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c index dff221bf27730e30b3e5bcca871b1e0efae1cbb4..57dcd2b33798c3e9230681bb5cfaee593903aa5a 100644 --- a/src/backend/access/transam/slru.c +++ b/src/backend/access/transam/slru.c @@ -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, diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 348906ea4ac13ea7d326541cda4b41689eb8c8d0..cfb864d09411c096ac735a09a343d885b9a44d54 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -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 $ * *------------------------------------------------------------------------- */ @@ -27,10 +27,10 @@ #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. diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index ed42bf133c7fc97a8016f16092f5d7eef5074b96..a19217a47b2631b1cafc0469ee7fa926ec66f7b1 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -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 * ---------------------------------------------------------------- diff --git a/src/backend/libpq/pqsignal.c b/src/backend/libpq/pqsignal.c index dc1f6ccc0871b6a0defb1c3deaef56b51e63d660..468c062aa4330cf041c125ea767cae8cb7fb00a5 100644 --- a/src/backend/libpq/pqsignal.c +++ b/src/backend/libpq/pqsignal.c @@ -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 @@ -46,6 +46,17 @@ #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 */ diff --git a/src/backend/main/main.c b/src/backend/main/main.c index 272d4cc0d0a0bad3cbbc73e522d4089219acf774..aee2da0731503398e960c985b2fb179383f30ffa 100644 --- a/src/backend/main/main.c +++ b/src/backend/main/main.c @@ -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 $ * *------------------------------------------------------------------------- */ @@ -34,12 +34,13 @@ #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 diff --git a/src/backend/postmaster/Makefile b/src/backend/postmaster/Makefile index b56881fc86eff6b97d363127c75cce2bdb1a864e..489c6d921123c8e93c84d9a80b0f7509d75897fa 100644 --- a/src/backend/postmaster/Makefile +++ b/src/backend/postmaster/Makefile @@ -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 index 0000000000000000000000000000000000000000..ce80a4feff7a6454152d6c154cca5c50296c975d --- /dev/null +++ b/src/backend/postmaster/bgwriter.c @@ -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); + } + } +} diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index a3a4e57c85594048e4f3ccd1f1ffe6484a93234f..c90749ca12763f717e3698ca4eb5fb922c3ee979 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -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" @@ -32,23 +32,25 @@ #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); } } diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 89a22815098955fc0fcc5d5050bac3d087ff26bd..e7186c01b39b5f575189a463e5564bbee7ad4dd0 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -37,14 +37,13 @@ * * * 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" @@ -113,22 +113,14 @@ #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) { diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 4f6772564a8df76148624befcdb5997c7a723138..f718e33cd598beddb09c76f8467e18f16017c162 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -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 */ diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c index 4ce5c98b577bf9cb21b14f2aea186388eb7c6aeb..69c460306b4199d51647abd2d3f409b95f2efd24 100644 --- a/src/backend/storage/ipc/ipci.c +++ b/src/backend/storage/ipc/ipci.c @@ -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 /* diff --git a/src/backend/storage/ipc/pmsignal.c b/src/backend/storage/ipc/pmsignal.c index b0fc1aea0ff2a847592bf3c5601ff7f1e7ff5dcf..4efa4adac6f80ec6d474eac77e924208f1028a75 100644 --- a/src/backend/storage/ipc/pmsignal.c +++ b/src/backend/storage/ipc/pmsignal.c @@ -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 */ +} diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 19ce44ff687f46e47adeece77b60763c7fa4db45..dbf5b414153f01238234c0bbfba1e6e7947c01b2 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -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; } diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 7acaf9117db22ff8921d29bd7872d46d93a55b45..556528d6d2d1fda6e2ba77bf01eb18f6c77c64e6 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -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. diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 39b69c6248c2e6fb34eacaf49c9e8da99a22d37d..4d6c246cea1a8ba483f14670889e1abc881d834b 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -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: diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index b76c4cb88b0941df0d3f66c7248c32e8464db0e4..e3adab82979d3f50aac2c5406d9702eda8b2a407 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -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" diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c index 85c3e23a019a9e2f1638f5454d97d891f3879ab5..2a22f666f6d29953e23e07d747c978e1a074024c 100644 --- a/src/backend/utils/init/globals.c +++ b/src/backend/utils/init/globals.c @@ -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; diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index 69d4d974099d0b8794af15f3c6f63ab7038be85c..e80187d57523403ad6ae1bd424f173f58e14d15a 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -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" diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 1620a8607c28c8e351ece360c3a8de19064b9bed..eda37c1be2c46c39010b4ed03cc0bc4cac8bac60 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -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" @@ -65,15 +67,10 @@ #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 }, diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index b0ebedcf329939b91825d399b1a3ab2ddbb576be..0e44e77446d650f98243117fbf26041903c1a378 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -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[]; diff --git a/src/include/bootstrap/bootstrap.h b/src/include/bootstrap/bootstrap.h index 7dd9c808fded8c933bf587b2f3dd32fe950f2c4e..21ed48286927ff3470fd93e72000f8ef955f249b 100644 --- a/src/include/bootstrap/bootstrap.h +++ b/src/include/bootstrap/bootstrap.h @@ -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 */ diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index e8e35fd6b58c24db5e060724eac34b8958fd9a9e..4561d2fcfb76a9f15ac145659e091f8e3218cbe2 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -13,11 +13,10 @@ * 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); diff --git a/src/include/pgstat.h b/src/include/pgstat.h index 8f7c4dc4515b7aaa1905f749d274b761f74de5d4..96d3af7ab051978f6ab4c957e3a1b8d049402e02 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -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 index 0000000000000000000000000000000000000000..c11af72e78945f91dfe76bfab00eeab7eabea886 --- /dev/null +++ b/src/include/postmaster/bgwriter.h @@ -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 index 0000000000000000000000000000000000000000..d349018f4b5ecf0e56a3843c93756328cb0a3bcb --- /dev/null +++ b/src/include/postmaster/postmaster.h @@ -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 */ diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h index 0aab9ad24f4466d39e3a2354cae535d0d031ad73..27752d412b56435ddbe61bf77adcd83554d1df92 100644 --- a/src/include/storage/bufmgr.h +++ b/src/include/storage/bufmgr.h @@ -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); diff --git a/src/include/storage/pmsignal.h b/src/include/storage/pmsignal.h index 688b83adab17bec45cc2013ecaf07e5695d96fc1..4180c95c735654e97c98d2ddb0c35ca27297349c 100644 --- a/src/include/storage/pmsignal.h +++ b/src/include/storage/pmsignal.h @@ -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 */ diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h index 97556ccbf1de1fb1a4df065c643d0c3e810f5c8e..1218e04fdfbc821077aca83d1ec1fd2260d0d91b 100644 --- a/src/include/tcop/tcopprot.h +++ b/src/include/tcop/tcopprot.h @@ -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;