[PATCH 05/16] Preliminary: Introduce Bgworker process

Поиск
Список
Период
Сортировка
От Andres Freund
Тема [PATCH 05/16] Preliminary: Introduce Bgworker process
Дата
Msg-id 1339586927-13156-5-git-send-email-andres@2ndquadrant.com
обсуждение исходный текст
Ответ на [RFC][PATCH] Logical Replication/BDR prototype and architecture  (Andres Freund <andres@2ndquadrant.com>)
Список pgsql-hackers
From: Simon Riggs <simon@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
100644src/backend/postmaster/bgworker.ccreate 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/postmastertop_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.oinclude $(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
thestartup, 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:
theseare children launched just * for the purpose of sending a friendly rejection message to a would-be * client.    We
musttrack 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;    /*
isit an autovacuum process? */
 
+    bool        is_bgworker;    /* is it a bgworker process? */    bool        dead_end;        /* is it going to send
anerror 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
tocommunicate 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
toa 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_tStartChildProcess(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("abortingany 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_OKotherwise. *
 
- * Note: if you change this code, also consider StartAutovacuumWorker.
+ * Note: if you change this code, also consider StartWorker. */static intBackendStartup(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
theresulting 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                /*
allOK */
 
-                return;
+                return bn->pid;            }            /*             * fork failed, fall through to report -- actual
errormessage 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
incase     * 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
neededin 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
bycanAcceptConnections().    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-usermode 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
inautovacuum 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
anyoverflow 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);staticbool check_maxconnections(int *newval, void **extra, GucSource source);static
voidassign_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
numberof connection slots reserved for superusers."),            NULL
 
@@ -8605,7 +8618,7 @@ show_tcp_keepalives_count(void)static boolcheck_maxconnections(int *newval, void **extra,
GucSourcesource){
 
-    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
voidassign_maxconnections(intnewval, 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 boolcheck_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
voidassign_autovacuum_max_workers(intnewval, 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



В списке pgsql-hackers по дате отправления:

Предыдущее
От: Andres Freund
Дата:
Сообщение: [PATCH 01/16] Overhaul walsender wakeup handling
Следующее
От: Andres Freund
Дата:
Сообщение: [PATCH 07/16] Log enough data into the wal to reconstruct logical changes from it if wal_level=logical