[PATCH 05/16] Preliminary: Introduce Bgworker process

From: Andres Freund <andres(at)2ndquadrant(dot)com>
To: pgsql-hackers(at)postgresql(dot)org
Subject: [PATCH 05/16] Preliminary: Introduce Bgworker process
Date: 2012-06-13 11:28:36
Message-ID: 1339586927-13156-5-git-send-email-andres@2ndquadrant.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

From: Simon Riggs <simon(at)2ndquadrant(dot)com>

Early prototype that allows for just 1 bgworker which calls a function called
do_applyprocess(). Expect major changes in this, but not in ways that would
effect the apply process.
---
src/backend/postmaster/Makefile | 4 +-
src/backend/postmaster/bgworker.c | 403 +++++++++++++++++++++++++
src/backend/postmaster/postmaster.c | 91 ++++--
src/backend/tcop/postgres.c | 5 +
src/backend/utils/init/miscinit.c | 5 +-
src/backend/utils/init/postinit.c | 3 +-
src/backend/utils/misc/guc.c | 37 ++-
src/backend/utils/misc/postgresql.conf.sample | 4 +
src/include/postmaster/bgworker.h | 29 ++
9 files changed, 550 insertions(+), 31 deletions(-)
create mode 100644 src/backend/postmaster/bgworker.c
create mode 100644 src/include/postmaster/bgworker.h

diff --git a/src/backend/postmaster/Makefile b/src/backend/postmaster/Makefile
index 3056b09..7b23353 100644
--- a/src/backend/postmaster/Makefile
+++ b/src/backend/postmaster/Makefile
@@ -12,7 +12,7 @@ subdir = src/backend/postmaster
top_builddir = ../../..
include $(top_builddir)/src/Makefile.global

-OBJS = autovacuum.o bgwriter.o fork_process.o pgarch.o pgstat.o postmaster.o \
- startup.o syslogger.o walwriter.o checkpointer.o
+OBJS = autovacuum.o bgworker.o bgwriter.o fork_process.o pgarch.o pgstat.o \
+ postmaster.o startup.o syslogger.o walwriter.o checkpointer.o

include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c
new file mode 100644
index 0000000..8144050
--- /dev/null
+++ b/src/backend/postmaster/bgworker.c
@@ -0,0 +1,403 @@
+/*-------------------------------------------------------------------------
+ *
+ * bgworker.c
+ *
+ * PostgreSQL Integrated Worker Daemon
+ *
+ * Background workers can execute arbitrary user code. A shared library
+ * can request creation of a worker using RequestAddinBGWorkerProcess().
+ *
+ * The worker process is forked from the postmaster and then attaches
+ * to shared memory similarly to an autovacuum worker and finally begins
+ * executing the supplied WorkerMain function.
+ *
+ * If the fork() call fails in the postmaster, it will try again later.
+ * Note that the failure can only be transient (fork failure due to
+ * high load, memory pressure, too many processes, etc); more permanent
+ * problems, like failure to connect to a database, are detected later in the
+ * worker and dealt with just by having the worker exit normally. Postmaster
+ * will launch a new worker again later.
+ *
+ * Note that there can be more than one worker in a database concurrently.
+ *
+ * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/postmaster/bgworker.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "access/heapam.h"
+#include "access/reloptions.h"
+#include "access/transam.h"
+#include "access/xact.h"
+#include "catalog/dependency.h"
+#include "catalog/namespace.h"
+#include "catalog/pg_database.h"
+#include "commands/dbcommands.h"
+#include "commands/vacuum.h"
+#include "libpq/pqsignal.h"
+#include "miscadmin.h"
+#include "pgstat.h"
+#include "postmaster/bgworker.h"
+#include "postmaster/fork_process.h"
+#include "postmaster/postmaster.h"
+#include "storage/bufmgr.h"
+#include "storage/ipc.h"
+#include "storage/latch.h"
+#include "storage/pmsignal.h"
+#include "storage/proc.h"
+#include "storage/procsignal.h"
+#include "storage/sinvaladt.h"
+#include "tcop/tcopprot.h"
+#include "utils/fmgroids.h"
+#include "utils/lsyscache.h"
+#include "utils/memutils.h"
+#include "utils/ps_status.h"
+#include "utils/rel.h"
+#include "utils/snapmgr.h"
+#include "utils/syscache.h"
+#include "utils/timestamp.h"
+#include "utils/tqual.h"
+
+
+/*
+ * GUC parameters
+ */
+int MaxWorkers;
+
+static int bgworker_addin_request = 0;
+static bool bgworker_addin_request_allowed = true;
+
+/* Flags to tell if we are in a worker process */
+static bool am_bgworker = false;
+
+/* Flags set by signal handlers */
+static volatile sig_atomic_t got_SIGHUP = false;
+static volatile sig_atomic_t got_SIGUSR2 = false;
+static volatile sig_atomic_t got_SIGTERM = false;
+
+static void bgworker_sigterm_handler(SIGNAL_ARGS);
+
+NON_EXEC_STATIC void BgWorkerMain(int argc, char *argv[]);
+
+static bool do_logicalapply(void);
+
+/********************************************************************
+ * BGWORKER CODE
+ ********************************************************************/
+
+/* SIGTERM: time to die */
+static void
+bgworker_sigterm_handler(SIGNAL_ARGS)
+{
+ int save_errno = errno;
+
+ got_SIGTERM = true;
+ if (MyProc)
+ SetLatch(&MyProc->procLatch);
+
+ errno = save_errno;
+}
+
+/*
+ * Main entry point for background worker process, to be called from the
+ * postmaster.
+ *
+ * This code is heavily based on autovacuum.c, q.v.
+ */
+int
+StartBgWorker(void)
+{
+ pid_t worker_pid;
+
+#ifdef EXEC_BACKEND
+ switch ((worker_pid = bgworker_forkexec()))
+#else
+ switch ((worker_pid = fork_process()))
+#endif
+ {
+ case -1:
+ ereport(LOG,
+ (errmsg("could not fork worker process: %m")));
+ return 0;
+
+#ifndef EXEC_BACKEND
+ case 0:
+ /* in postmaster child ... */
+ /* Close the postmaster's sockets */
+ ClosePostmasterPorts(false);
+
+ /* Lose the postmaster's on-exit routines */
+ on_exit_reset();
+
+ BgWorkerMain(0, NULL);
+ break;
+#endif
+ default:
+ return (int) worker_pid;
+ }
+
+ /* shouldn't get here */
+ return 0;
+}
+
+/*
+ * BgWorkerMain
+ */
+NON_EXEC_STATIC void
+BgWorkerMain(int argc, char *argv[])
+{
+ sigjmp_buf local_sigjmp_buf;
+ //Oid dbid = 12037; /* kluge to set dbid for "Postgres" */
+ bool init = false;
+
+ /* we are a postmaster subprocess now */
+ IsUnderPostmaster = true;
+ am_bgworker = true;
+
+ /* reset MyProcPid */
+ MyProcPid = getpid();
+
+ /* record Start Time for logging */
+ MyStartTime = time(NULL);
+
+ /* Identify myself via ps */
+ init_ps_display("worker process", "", "", "");
+
+ SetProcessingMode(InitProcessing);
+
+ /*
+ * If possible, make this process a group leader, so that the postmaster
+ * can signal any child processes too. (autovacuum probably never has any
+ * child processes, but for consistency we make all postmaster child
+ * processes do this.)
+ */
+#ifdef HAVE_SETSID
+ if (setsid() < 0)
+ elog(FATAL, "setsid() failed: %m");
+#endif
+
+ /*
+ * Set up signal handlers. We operate on databases much like a regular
+ * backend, so we use the same signal handling. See equivalent code in
+ * tcop/postgres.c.
+ *
+ * Currently, we don't pay attention to postgresql.conf changes that
+ * happen during a single daemon iteration, so we can ignore SIGHUP.
+ */
+ pqsignal(SIGHUP, SIG_IGN);
+
+ /*
+ * SIGINT is used to signal canceling the current action; SIGTERM
+ * means abort and exit cleanly, and SIGQUIT means abandon ship.
+ */
+ pqsignal(SIGINT, StatementCancelHandler);
+ pqsignal(SIGTERM, bgworker_sigterm_handler); // was die);
+ pqsignal(SIGQUIT, quickdie);
+ pqsignal(SIGALRM, handle_sig_alarm);
+
+ pqsignal(SIGPIPE, SIG_IGN);
+ pqsignal(SIGUSR1, procsignal_sigusr1_handler);
+ pqsignal(SIGUSR2, SIG_IGN);
+ pqsignal(SIGFPE, FloatExceptionHandler);
+ pqsignal(SIGCHLD, SIG_DFL);
+
+ /* Early initialization */
+ BaseInit();
+
+ /*
+ * Create a per-backend PGPROC struct in shared memory, except in the
+ * EXEC_BACKEND case where this was done in SubPostmasterMain. We must do
+ * this before we can use LWLocks (and in the EXEC_BACKEND case we already
+ * had to do some stuff with LWLocks).
+ */
+#ifndef EXEC_BACKEND
+ InitProcess();
+#endif
+
+ /*
+ * If an exception is encountered, processing resumes here.
+ *
+ * See notes in postgres.c about the design of this coding.
+ */
+ if (sigsetjmp(local_sigjmp_buf, 1) != 0)
+ {
+ /* Prevents interrupts while cleaning up */
+ HOLD_INTERRUPTS();
+
+ /* Report the error to the server log */
+ EmitErrorReport();
+
+ /*
+ * We can now go away. Note that because we called InitProcess, a
+ * callback was registered to do ProcKill, which will clean up
+ * necessary state.
+ */
+ proc_exit(0);
+ }
+
+ /* We can now handle ereport(ERROR) */
+ PG_exception_stack = &local_sigjmp_buf;
+
+ PG_SETMASK(&UnBlockSig);
+
+ /*
+ * Force zero_damaged_pages OFF in a worker process, even if it is set
+ * in postgresql.conf. We don't really want such a dangerous option being
+ * applied non-interactively.
+ */
+ SetConfigOption("zero_damaged_pages", "false", PGC_SUSET, PGC_S_OVERRIDE);
+
+ /*
+ * Force statement_timeout to zero to avoid a timeout setting from
+ * preventing regular maintenance from being executed.
+ */
+ SetConfigOption("statement_timeout", "0", PGC_SUSET, PGC_S_OVERRIDE);
+
+ /*
+ * Force default_transaction_isolation to READ COMMITTED. We don't
+ * want to pay the overhead of serializable mode, nor add any risk
+ * of causing deadlocks or delaying other transactions.
+ */
+ SetConfigOption("default_transaction_isolation", "read committed",
+ PGC_SUSET, PGC_S_OVERRIDE);
+
+ /*
+ * Force synchronous replication off to allow regular maintenance even if
+ * we are waiting for standbys to connect. This is important to ensure we
+ * aren't blocked from performing anti-wraparound tasks.
+ */
+ if (synchronous_commit > SYNCHRONOUS_COMMIT_LOCAL_FLUSH)
+ SetConfigOption("synchronous_commit", "local",
+ PGC_SUSET, PGC_S_OVERRIDE);
+
+ for (;;)
+ {
+ bool not_idle;
+
+ /* the normal shutdown case */
+ if (got_SIGTERM)
+ break;
+
+ if (got_SIGHUP)
+ {
+ got_SIGHUP = false;
+ ProcessConfigFile(PGC_SIGHUP);
+ }
+
+ if (!init)
+ {
+ char dbname[NAMEDATALEN] = "postgres";
+
+ /*
+ * Connect to the selected database
+ *
+ * Note: if we have selected a just-deleted database (due to using
+ * stale stats info), we'll fail and exit here.
+ *
+ * Note that MyProcPort is not setup correctly, so normal
+ * authentication will simply fail. This is bypassed by moving
+ * straight to superuser mode, using same trick as autovacuum.
+ */
+ InitPostgres(dbname, InvalidOid, NULL, NULL);
+ SetProcessingMode(NormalProcessing);
+ ereport(LOG,
+ (errmsg("starting worker process on database \"%s\"", dbname)));
+
+ if (PostAuthDelay)
+ pg_usleep(PostAuthDelay * 1000000L);
+
+ CurrentResourceOwner = ResourceOwnerCreate(NULL, "worker process");
+
+ init = true;
+ }
+
+ /*
+ * If we're initialised correctly we can call the worker code.
+ */
+ if (init)
+ not_idle = do_logicalapply();
+
+ if(!not_idle){
+ /* Just for test and can be removed. */
+ pg_usleep(100000L);
+ }
+ }
+
+ /* Normal exit from the bgworker is here */
+ ereport(LOG,
+ (errmsg("worker shutting down")));
+
+ /* All done, go away */
+ proc_exit(0);
+}
+
+bool
+IsWorkerProcess(void)
+{
+ return am_bgworker;
+}
+
+/*
+ * RequestAddinBgWorkerProcess
+ * Request a background worker process
+ *
+ * This is only useful if called from the _PG_init hook of a library that
+ * is loaded into the postmaster via shared_preload_libraries. Once
+ * shared memory has been allocated, calls will be ignored. (We could
+ * raise an error, but it seems better to make it a no-op, so that
+ * libraries containing such calls can be reloaded if needed.)
+ */
+void
+RequestAddinBgWorkerProcess(const char *WorkerName,
+ void *Main,
+ const char *DBname)
+{
+ if (IsUnderPostmaster || !bgworker_addin_request_allowed)
+ return; /* too late */
+ bgworker_addin_request++;
+}
+
+/*
+ * Compute number of BgWorkers to allocate.
+ */
+int
+NumBgWorkers(void)
+{
+ return 1;
+
+#ifdef UNUSED
+ int numWorkers;
+
+ /*
+ * Include number of workers required by server, for example,
+ * parallel query worker tasks.
+ */
+
+ /*
+ * Add any requested by loadable modules.
+ */
+ bgworker_addin_request_allowed = false;
+ numWorkers += bgworker_addin_request;
+
+ return numWorkers;
+#endif
+}
+
+static bool
+do_logicalapply(void)
+{
+ elog(LOG, "doing logical apply");
+ return false;
+}
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index eeea933..71cfd6d 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -103,6 +103,7 @@
#include "miscadmin.h"
#include "pgstat.h"
#include "postmaster/autovacuum.h"
+#include "postmaster/bgworker.h"
#include "postmaster/fork_process.h"
#include "postmaster/pgarch.h"
#include "postmaster/postmaster.h"
@@ -131,7 +132,7 @@
* children we have and send them appropriate signals when necessary.
*
* "Special" children such as the startup, bgwriter and autovacuum launcher
- * tasks are not in this list. Autovacuum worker and walsender processes are
+ * tasks are not in this list. All worker and walsender processes are
* in it. Also, "dead_end" children are in it: these are children launched just
* for the purpose of sending a friendly rejection message to a would-be
* client. We must track them because they are attached to shared memory,
@@ -144,6 +145,7 @@ typedef struct bkend
long cancel_key; /* cancel key for cancels for this backend */
int child_slot; /* PMChildSlot for this backend, if any */
bool is_autovacuum; /* is it an autovacuum process? */
+ bool is_bgworker; /* is it a bgworker process? */
bool dead_end; /* is it going to send an error and quit? */
Dlelem elem; /* list link in BackendList */
} Backend;
@@ -216,6 +218,8 @@ static pid_t StartupPID = 0,
PgStatPID = 0,
SysLoggerPID = 0;

+static pid_t *BgWorkerPID; /* Array of PIDs of bg workers */
+
/* Startup/shutdown state */
#define NoShutdown 0
#define SmartShutdown 1
@@ -303,6 +307,8 @@ static volatile sig_atomic_t start_autovac_launcher = false;
/* the launcher needs to be signalled to communicate some condition */
static volatile bool avlauncher_needs_signal = false;

+static int NWorkers;
+
/*
* State for assigning random salts and cancel keys.
* Also, the global MyCancelKey passes the cancel key assigned to a given
@@ -366,12 +372,16 @@ static bool SignalSomeChildren(int signal, int targets);
#define BACKEND_TYPE_NORMAL 0x0001 /* normal backend */
#define BACKEND_TYPE_AUTOVAC 0x0002 /* autovacuum worker process */
#define BACKEND_TYPE_WALSND 0x0004 /* walsender process */
-#define BACKEND_TYPE_ALL 0x0007 /* OR of all the above */
+#define BACKEND_TYPE_BGWORKER 0x0008 /* general bgworker process */
+#define BACKEND_TYPE_ALL 0x000F /* OR of all the above */
+
+#define BACKEND_TYPE_WORKER (BACKEND_TYPE_AUTOVAC | BACKEND_TYPE_BGWORKER)

static int CountChildren(int target);
+static void StartBackgroundWorkers(void);
static bool CreateOptsFile(int argc, char *argv[], char *fullprogname);
static pid_t StartChildProcess(AuxProcType type);
-static void StartAutovacuumWorker(void);
+static int StartWorker(bool is_autovacuum);
static void InitPostmasterDeathWatchHandle(void);

#ifdef EXEC_BACKEND
@@ -1037,7 +1047,7 @@ PostmasterMain(int argc, char *argv[])
* handling setup of child processes. See tcop/postgres.c,
* bootstrap/bootstrap.c, postmaster/bgwriter.c, postmaster/walwriter.c,
* postmaster/autovacuum.c, postmaster/pgarch.c, postmaster/pgstat.c,
- * postmaster/syslogger.c and postmaster/checkpointer.c.
+ * postmaster/syslogger.c, postmaster/bgworker.c and postmaster/checkpointer.c
*/
pqinitmask();
PG_SETMASK(&BlockSig);
@@ -1085,6 +1095,17 @@ PostmasterMain(int argc, char *argv[])
autovac_init();

/*
+ * Allocate background workers actually required.
+ */
+ NWorkers = NumBgWorkers();
+ if (NWorkers > 0)
+ {
+ BgWorkerPID = (pid_t *) MemoryContextAlloc(TopMemoryContext,
+ NWorkers * sizeof(pid_t));
+ memset(BgWorkerPID, 0, NWorkers * sizeof(pid_t));
+ }
+
+ /*
* Load configuration files for client authentication.
*/
if (!load_hba())
@@ -1428,6 +1449,10 @@ ServerLoop(void)
kill(AutoVacPID, SIGUSR2);
}

+ /* Check all the workers requested are running. */
+ if (pmState == PM_RUN)
+ StartBackgroundWorkers();
+
/*
* Touch the socket and lock file every 58 minutes, to ensure that
* they are not removed by overzealous /tmp-cleaning tasks. We assume
@@ -2133,8 +2158,8 @@ pmdie(SIGNAL_ARGS)
if (pmState == PM_RUN || pmState == PM_RECOVERY ||
pmState == PM_HOT_STANDBY || pmState == PM_STARTUP)
{
- /* autovacuum workers are told to shut down immediately */
- SignalSomeChildren(SIGTERM, BACKEND_TYPE_AUTOVAC);
+ /* workers are told to shut down immediately */
+ SignalSomeChildren(SIGTERM, BACKEND_TYPE_WORKER);
/* and the autovac launcher too */
if (AutoVacPID != 0)
signal_child(AutoVacPID, SIGTERM);
@@ -2203,9 +2228,9 @@ pmdie(SIGNAL_ARGS)
{
ereport(LOG,
(errmsg("aborting any active transactions")));
- /* shut down all backends and autovac workers */
+ /* shut down all backends and workers */
SignalSomeChildren(SIGTERM,
- BACKEND_TYPE_NORMAL | BACKEND_TYPE_AUTOVAC);
+ BACKEND_TYPE_NORMAL | BACKEND_TYPE_WORKER);
/* and the autovac launcher too */
if (AutoVacPID != 0)
signal_child(AutoVacPID, SIGTERM);
@@ -2396,6 +2421,7 @@ reaper(SIGNAL_ARGS)
PgArchPID = pgarch_start();
if (PgStatPID == 0)
PgStatPID = pgstat_start();
+ StartBackgroundWorkers();

/* at this point we are really open for business */
ereport(LOG,
@@ -2963,7 +2989,7 @@ PostmasterStateMachine(void)
* later after writing the checkpoint record, like the archiver
* process.
*/
- if (CountChildren(BACKEND_TYPE_NORMAL | BACKEND_TYPE_AUTOVAC) == 0 &&
+ if (CountChildren(BACKEND_TYPE_NORMAL | BACKEND_TYPE_WORKER) == 0 &&
StartupPID == 0 &&
WalReceiverPID == 0 &&
BgWriterPID == 0 &&
@@ -3202,6 +3228,8 @@ SignalSomeChildren(int signal, int target)

if (bp->is_autovacuum)
child = BACKEND_TYPE_AUTOVAC;
+ else if (bp->is_bgworker)
+ child = BACKEND_TYPE_BGWORKER;
else if (IsPostmasterChildWalSender(bp->child_slot))
child = BACKEND_TYPE_WALSND;
else
@@ -3224,7 +3252,7 @@ SignalSomeChildren(int signal, int target)
*
* returns: STATUS_ERROR if the fork failed, STATUS_OK otherwise.
*
- * Note: if you change this code, also consider StartAutovacuumWorker.
+ * Note: if you change this code, also consider StartWorker.
*/
static int
BackendStartup(Port *port)
@@ -3325,6 +3353,7 @@ BackendStartup(Port *port)
*/
bn->pid = pid;
bn->is_autovacuum = false;
+ bn->is_bgworker = false;
DLInitElem(&bn->elem, bn);
DLAddHead(BackendList, &bn->elem);
#ifdef EXEC_BACKEND
@@ -4302,7 +4331,7 @@ sigusr1_handler(SIGNAL_ARGS)
if (CheckPostmasterSignal(PMSIGNAL_START_AUTOVAC_WORKER))
{
/* The autovacuum launcher wants us to start a worker process. */
- StartAutovacuumWorker();
+ (void) StartWorker(true);
}

if (CheckPostmasterSignal(PMSIGNAL_START_WALRECEIVER) &&
@@ -4448,6 +4477,8 @@ CountChildren(int target)

if (bp->is_autovacuum)
child = BACKEND_TYPE_AUTOVAC;
+ else if (bp->is_bgworker)
+ child = BACKEND_TYPE_BGWORKER;
else if (IsPostmasterChildWalSender(bp->child_slot))
child = BACKEND_TYPE_WALSND;
else
@@ -4570,16 +4601,16 @@ StartChildProcess(AuxProcType type)
}

/*
- * StartAutovacuumWorker
- * Start an autovac worker process.
+ * StartWorker
+ * Start a worker process either for autovacuum or more generally.
*
* This function is here because it enters the resulting PID into the
* postmaster's private backends list.
*
* NB -- this code very roughly matches BackendStartup.
*/
-static void
-StartAutovacuumWorker(void)
+static int
+StartWorker(bool is_autovacuum)
{
Backend *bn;

@@ -4608,22 +4639,26 @@ StartAutovacuumWorker(void)
bn->dead_end = false;
bn->child_slot = MyPMChildSlot = AssignPostmasterChildSlot();

- bn->pid = StartAutoVacWorker();
+ if (is_autovacuum)
+ bn->pid = StartAutoVacWorker();
+ else
+ bn->pid = StartBgWorker();
+
if (bn->pid > 0)
{
- bn->is_autovacuum = true;
+ bn->is_autovacuum = is_autovacuum;
DLInitElem(&bn->elem, bn);
DLAddHead(BackendList, &bn->elem);
#ifdef EXEC_BACKEND
ShmemBackendArrayAdd(bn);
#endif
/* all OK */
- return;
+ return bn->pid;
}

/*
* fork failed, fall through to report -- actual error message was
- * logged by StartAutoVacWorker
+ * logged by Start...Worker
*/
(void) ReleasePostmasterChildSlot(bn->child_slot);
free(bn);
@@ -4643,11 +4678,25 @@ StartAutovacuumWorker(void)
* quick succession between the autovac launcher and postmaster in case
* things get ugly.
*/
- if (AutoVacPID != 0)
+ if (is_autovacuum && AutoVacPID != 0)
{
AutoVacWorkerFailed();
avlauncher_needs_signal = true;
}
+
+ return 0;
+}
+
+static void
+StartBackgroundWorkers(void)
+{
+ int i;
+
+ for (i = 0; i < NWorkers; i++)
+ {
+ if (BgWorkerPID[i] == 0)
+ BgWorkerPID[i] = StartWorker(false);
+ }
}

/*
@@ -4687,7 +4736,7 @@ CreateOptsFile(int argc, char *argv[], char *fullprogname)
*
* This reports the number of entries needed in per-child-process arrays
* (the PMChildFlags array, and if EXEC_BACKEND the ShmemBackendArray).
- * These arrays include regular backends, autovac workers and walsenders,
+ * These arrays include regular backends, all workers and walsenders,
* but not special children nor dead_end children. This allows the arrays
* to have a fixed maximum size, to wit the same too-many-children limit
* enforced by canAcceptConnections(). The exact value isn't too critical
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 51b6df5..5aead05 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -56,6 +56,7 @@
#include "parser/analyze.h"
#include "parser/parser.h"
#include "postmaster/autovacuum.h"
+#include "postmaster/bgworker.h"
#include "postmaster/postmaster.h"
#include "replication/walsender.h"
#include "rewrite/rewriteHandler.h"
@@ -2841,6 +2842,10 @@ ProcessInterrupts(void)
ereport(FATAL,
(errcode(ERRCODE_ADMIN_SHUTDOWN),
errmsg("terminating autovacuum process due to administrator command")));
+ else if (IsWorkerProcess())
+ ereport(FATAL,
+ (errcode(ERRCODE_ADMIN_SHUTDOWN),
+ errmsg("terminating worker process due to administrator command")));
else if (RecoveryConflictPending && RecoveryConflictRetryable)
{
pgstat_report_recovery_conflict(RecoveryConflictReason);
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index fb376a0..f7ae60a 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -33,6 +33,7 @@
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
+#include "postmaster/bgworker.h"
#include "postmaster/postmaster.h"
#include "storage/fd.h"
#include "storage/ipc.h"
@@ -498,9 +499,9 @@ InitializeSessionUserIdStandalone(void)
{
/*
* This function should only be called in single-user mode and in
- * autovacuum workers.
+ * autovacuum or background workers.
*/
- AssertState(!IsUnderPostmaster || IsAutoVacuumWorkerProcess());
+ AssertState(!IsUnderPostmaster || IsAutoVacuumWorkerProcess() || IsWorkerProcess());

/* call only once */
AssertState(!OidIsValid(AuthenticatedUserId));
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 1baa67d..3208b5e7 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -36,6 +36,7 @@
#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "postmaster/postmaster.h"
+#include "postmaster/bgworker.h"
#include "replication/walsender.h"
#include "storage/bufmgr.h"
#include "storage/fd.h"
@@ -584,7 +585,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
* In standalone mode and in autovacuum worker processes, we use a fixed
* ID, otherwise we figure it out from the authenticated user name.
*/
- if (bootstrap || IsAutoVacuumWorkerProcess())
+ if (bootstrap || IsAutoVacuumWorkerProcess() || IsWorkerProcess())
{
InitializeSessionUserIdStandalone();
am_superuser = true;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index b756e58..93c798b 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -52,6 +52,7 @@
#include "parser/scansup.h"
#include "pgstat.h"
#include "postmaster/autovacuum.h"
+#include "postmaster/bgworker.h"
#include "postmaster/bgwriter.h"
#include "postmaster/postmaster.h"
#include "postmaster/syslogger.h"
@@ -107,7 +108,7 @@
* removed, we still could not exceed INT_MAX/4 because some places compute
* 4*MaxBackends without any overflow check. This is rechecked in
* check_maxconnections, since MaxBackends is computed as MaxConnections
- * plus autovacuum_max_workers plus one (for the autovacuum launcher).
+ * plus max_workers plus autovacuum_max_workers plus one (for the autovacuum launcher).
*/
#define MAX_BACKENDS 0x7fffff

@@ -197,6 +198,8 @@ static const char *show_tcp_keepalives_interval(void);
static const char *show_tcp_keepalives_count(void);
static bool check_maxconnections(int *newval, void **extra, GucSource source);
static void assign_maxconnections(int newval, void *extra);
+static bool check_maxworkers(int *newval, void **extra, GucSource source);
+static void assign_maxworkers(int newval, void *extra);
static bool check_autovacuum_max_workers(int *newval, void **extra, GucSource source);
static void assign_autovacuum_max_workers(int newval, void *extra);
static bool check_effective_io_concurrency(int *newval, void **extra, GucSource source);
@@ -1605,6 +1608,16 @@ static struct config_int ConfigureNamesInt[] =
},

{
+ {"max_workers", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
+ gettext_noop("Sets the maximum number of background worker processes."),
+ NULL
+ },
+ &MaxWorkers,
+ 10, 1, MAX_BACKENDS,
+ check_maxworkers, assign_maxworkers, NULL
+ },
+
+ {
{"superuser_reserved_connections", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
gettext_noop("Sets the number of connection slots reserved for superusers."),
NULL
@@ -8605,7 +8618,7 @@ show_tcp_keepalives_count(void)
static bool
check_maxconnections(int *newval, void **extra, GucSource source)
{
- if (*newval + autovacuum_max_workers + 1 > MAX_BACKENDS)
+ if (*newval + MaxWorkers + autovacuum_max_workers + 1 > MAX_BACKENDS)
return false;
return true;
}
@@ -8613,13 +8626,27 @@ check_maxconnections(int *newval, void **extra, GucSource source)
static void
assign_maxconnections(int newval, void *extra)
{
- MaxBackends = newval + autovacuum_max_workers + 1;
+ MaxBackends = newval + MaxWorkers + autovacuum_max_workers + 1;
+}
+
+static bool
+check_maxworkers(int *newval, void **extra, GucSource source)
+{
+ if (*newval + MaxConnections + autovacuum_max_workers + 1 > MAX_BACKENDS)
+ return false;
+ return true;
+}
+
+static void
+assign_maxworkers(int newval, void *extra)
+{
+ MaxBackends = newval + MaxConnections + autovacuum_max_workers + 1;
}

static bool
check_autovacuum_max_workers(int *newval, void **extra, GucSource source)
{
- if (MaxConnections + *newval + 1 > MAX_BACKENDS)
+ if (MaxConnections + MaxWorkers + *newval + 1 > MAX_BACKENDS)
return false;
return true;
}
@@ -8627,7 +8654,7 @@ check_autovacuum_max_workers(int *newval, void **extra, GucSource source)
static void
assign_autovacuum_max_workers(int newval, void *extra)
{
- MaxBackends = MaxConnections + newval + 1;
+ MaxBackends = MaxConnections + MaxWorkers + newval + 1;
}

static bool
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index fa75d00..ce3fc08 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -148,6 +148,10 @@
#bgwriter_lru_maxpages = 100 # 0-1000 max buffers written/round
#bgwriter_lru_multiplier = 2.0 # 0-10.0 multipler on buffers scanned/round

+# - Background Workers -
+#max_workers = 10 # max number of general worker subprocesses
+ # (change requires restart)
+
# - Asynchronous Behavior -

#effective_io_concurrency = 1 # 1-1000; 0 disables prefetching
diff --git a/src/include/postmaster/bgworker.h b/src/include/postmaster/bgworker.h
new file mode 100644
index 0000000..92d0a75
--- /dev/null
+++ b/src/include/postmaster/bgworker.h
@@ -0,0 +1,29 @@
+/*-------------------------------------------------------------------------
+ *
+ * bgworker.h
+ * header file for integrated background worker daemon
+ *
+ *
+ * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/postmaster/bgworker.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef BGWORKER_H
+#define BGWORKER_H
+
+
+/* GUC variables */
+int MaxWorkers;
+
+extern int StartBgWorker(void);
+extern int NumBgWorkers(void);
+
+extern bool IsWorkerProcess(void);
+extern void RequestAddinBgWorkerProcess(const char *WorkerName,
+ void *Main,
+ const char *DBname);
+
+#endif /* BGWORKER_H */
--
1.7.10.rc3.3.g19a6c.dirty

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Andres Freund 2012-06-13 11:28:37 [PATCH 06/16] Add support for a generic wal reading facility dubbed XLogReader
Previous Message Andres Freund 2012-06-13 11:28:35 [PATCH 04/16] Add embedded list interface (header only)