From: Simon Riggs <si...@2ndquadrant.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


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to