index b0dde7564d86093e9aa4424ab562151e3ebb3f6f..f7126388af18ec4e51582eb4a8ab83e03f87369e 100644 (file)
The <filename>worker_spi</> contrib module contains a working example,
which demonstrates some useful techniques.
</para>
+
+ <para>
+ The maximum number of registered background workers is limited by
+ <xref linkend="guc-max-worker-processes">.
+ </para>
</chapter>
index 437dbb7711c712a656d01fef6bb883e712f04db9..9126bc37cb54c42a89ab2db0626e5db6fd283d38 100644 (file)
</para>
</listitem>
</varlistentry>
+
+ <varlistentry id="guc-max-worker-processes" xreflabel="max_worrker_processes">
+ <term><varname>max_worker_processes</varname> (<type>integer</type>)</term>
+ <indexterm>
+ <primary><varname>max_worker_processes</> configuration parameter</primary>
+ </indexterm>
+ <listitem>
+ <para>
+ Sets the maximum number of background processes that the system
+ can support. This parameter can only be set at server start.
+ </para>
+
+ <para>
+ When running a standby server, you must set this parameter to the
+ same or higher value than on the master server. Otherwise, queries
+ will not be allowed in the standby server.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</sect2>
</sect1>
index 12370521d453beeda4f6e8aa42240bfed26e6e76..1b36f9a88a539b5eac47342f2e11346dde302d2e 100644 (file)
@@ -117,8 +117,9 @@ xlog_desc(StringInfo buf, uint8 xl_info, char *rec)
}
}
- appendStringInfo(buf, "parameter change: max_connections=%d max_prepared_xacts=%d max_locks_per_xact=%d wal_level=%s",
+ appendStringInfo(buf, "parameter change: max_connections=%d max_worker_processes=%d max_prepared_xacts=%d max_locks_per_xact=%d wal_level=%s",
xlrec.MaxConnections,
+ xlrec.max_worker_processes,
xlrec.max_prepared_xacts,
xlrec.max_locks_per_xact,
wal_level_str);
index 0ce661bf9f4432180b9812b82726f76ebe8745bc..4220859c8a4a26bae0e0f9d4b8eea11cd5ac7672 100644 (file)
/* Set important parameter values for use when replaying WAL */
ControlFile->MaxConnections = MaxConnections;
+ ControlFile->max_worker_processes = max_worker_processes;
ControlFile->max_prepared_xacts = max_prepared_xacts;
ControlFile->max_locks_per_xact = max_locks_per_xact;
ControlFile->wal_level = wal_level;
RecoveryRequiresIntParameter("max_connections",
MaxConnections,
ControlFile->MaxConnections);
+ RecoveryRequiresIntParameter("max_worker_processes",
+ max_worker_processes,
+ ControlFile->max_worker_processes);
RecoveryRequiresIntParameter("max_prepared_transactions",
max_prepared_xacts,
ControlFile->max_prepared_xacts);
{
if (wal_level != ControlFile->wal_level ||
MaxConnections != ControlFile->MaxConnections ||
+ max_worker_processes != ControlFile->max_worker_processes ||
max_prepared_xacts != ControlFile->max_prepared_xacts ||
max_locks_per_xact != ControlFile->max_locks_per_xact)
{
xl_parameter_change xlrec;
xlrec.MaxConnections = MaxConnections;
+ xlrec.max_worker_processes = max_worker_processes;
xlrec.max_prepared_xacts = max_prepared_xacts;
xlrec.max_locks_per_xact = max_locks_per_xact;
xlrec.wal_level = wal_level;
}
ControlFile->MaxConnections = MaxConnections;
+ ControlFile->max_worker_processes = max_worker_processes;
ControlFile->max_prepared_xacts = max_prepared_xacts;
ControlFile->max_locks_per_xact = max_locks_per_xact;
ControlFile->wal_level = wal_level;
LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
ControlFile->MaxConnections = xlrec.MaxConnections;
+ ControlFile->max_worker_processes = xlrec.max_worker_processes;
ControlFile->max_prepared_xacts = xlrec.max_prepared_xacts;
ControlFile->max_locks_per_xact = xlrec.max_locks_per_xact;
ControlFile->wal_level = xlrec.wal_level;
index 15fd4c90eaae1f056b8943bb1471eb1dd8d2aee4..e3b32cbe08044ea3f0797a54e18414013fc8295d 100644 (file)
static void sigusr1_handler(SIGNAL_ARGS);
static void startup_die(SIGNAL_ARGS);
static void dummy_handler(SIGNAL_ARGS);
-static int GetNumRegisteredBackgroundWorkers(int flags);
static void StartupPacketTimeoutHandler(void);
static void CleanupBackend(int pid, int exitstatus);
static bool CleanupBackgroundWorker(int pid, int exitstatus);
MaxLivePostmasterChildren(void)
{
return 2 * (MaxConnections + autovacuum_max_workers + 1 +
- GetNumRegisteredBackgroundWorkers(0));
+ max_worker_processes);
}
/*
@@ -5226,7 +5225,6 @@ RegisterBackgroundWorker(BackgroundWorker *worker)
{
RegisteredBgWorker *rw;
int namelen = strlen(worker->bgw_name);
- static int maxworkers;
static int numworkers = 0;
#ifdef EXEC_BACKEND
static int BackgroundWorkerCookie = 1;
#endif
- /* initialize upper limit on first call */
- if (numworkers == 0)
- maxworkers = MAX_BACKENDS -
- (MaxConnections + autovacuum_max_workers + 1);
-
if (!IsUnderPostmaster)
ereport(LOG,
(errmsg("registering background worker: %s", worker->bgw_name)));
/*
* Enforce maximum number of workers. Note this is overly restrictive: we
* could allow more non-shmem-connected workers, because these don't count
- * towards the MAX_BACKENDS limit elsewhere. This doesn't really matter
- * for practical purposes; several million processes would need to run on
- * a single server.
+ * towards the MAX_BACKENDS limit elsewhere. For now, it doesn't seem
+ * important to relax this restriction.
*/
- if (++numworkers > maxworkers)
+ if (++numworkers > max_worker_processes)
{
ereport(LOG,
(errcode(ERRCODE_CONFIGURATION_LIMIT_EXCEEDED),
errmsg("too many background workers"),
errdetail("Up to %d background workers can be registered with the current settings.",
- maxworkers)));
+ max_worker_processes),
+ errhint("Consider increasing the configuration parameter \"max_worker_processes\".")));
return;
}
proc_exit(0);
}
-/*
- * Return the number of background workers registered that have at least
- * one of the passed flag bits set.
- */
-static int
-GetNumRegisteredBackgroundWorkers(int flags)
-{
- slist_iter iter;
- int count = 0;
-
- slist_foreach(iter, &BackgroundWorkerList)
- {
- RegisteredBgWorker *rw;
-
- rw = slist_container(RegisteredBgWorker, rw_lnode, iter.cur);
-
- if (flags != 0 &&
- !(rw->rw_worker.bgw_flags & flags))
- continue;
-
- count++;
- }
-
- return count;
-}
-
-/*
- * Return the number of bgworkers that need to have PGPROC entries.
- */
-int
-GetNumShmemAttachedBgworkers(void)
-{
- return GetNumRegisteredBackgroundWorkers(BGWORKER_SHMEM_ACCESS);
-}
-
#ifdef EXEC_BACKEND
static pid_t
bgworker_forkexec(int cookie)
index 6d72a637f740cc4573d305e44fb2b76bd51cd8d6..25bd5285669ded1e2b194b29d2fc327bbda51c7a 100644 (file)
* running out when trying to start another backend is a common failure.
* So, now we grab enough semaphores to support the desired max number
* of backends immediately at initialization --- if the sysadmin has set
- * MaxConnections or autovacuum_max_workers higher than his kernel will
- * support, he'll find out sooner rather than later. (The number of
- * background worker processes registered by loadable modules is also taken
- * into consideration.)
+ * MaxConnections, max_worker_processes, or autovacuum_max_workers higher
+ * than his kernel will support, he'll find out sooner rather than later.
*
* Another reason for creating semaphores here is that the semaphore
* implementation typically requires us to create semaphores in the
index 9f51929191d5b23d12e13068843117a988df3436..33efb3c3cca933f69aa16286aa8c0e68d67bb754 100644 (file)
*/
int NBuffers = 1000;
int MaxConnections = 90;
+int max_worker_processes = 8;
int MaxBackends = 0;
int VacuumCostPageHit = 1; /* GUC parameters for vacuum */
index 127f9273e85795f37ce6bbe7807b926296e38886..2c7f0f1764113602504386f4972371a97e8fa332 100644 (file)
/* the extra unit accounts for the autovacuum launcher */
MaxBackends = MaxConnections + autovacuum_max_workers + 1 +
- GetNumShmemAttachedBgworkers();
+ + max_worker_processes;
/* internal error because the values were all checked previously */
if (MaxBackends > MAX_BACKENDS)
index 3a7653698d35864d2f4851e55acdb84ba3d271d3..d6200616de8df517096fa9f9540887ad1a476439 100644 (file)
@@ -190,6 +190,7 @@ static const char *show_tcp_keepalives_idle(void);
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 bool check_max_worker_processes(int *newval, void **extra, GucSource source);
static bool check_autovacuum_max_workers(int *newval, void **extra, GucSource source);
static bool check_effective_io_concurrency(int *newval, void **extra, GucSource source);
static void assign_effective_io_concurrency(int newval, void *extra);
check_effective_io_concurrency, assign_effective_io_concurrency, NULL
},
+ {
+ {"max_worker_processes",
+ PGC_POSTMASTER,
+ RESOURCES_ASYNCHRONOUS,
+ gettext_noop("Maximum number of concurrent worker processes."),
+ NULL,
+ },
+ &max_worker_processes,
+ 8, 1, MAX_BACKENDS,
+ check_max_worker_processes, NULL, NULL
+ },
+
{
{"log_rotation_age", PGC_SIGHUP, LOGGING_WHERE,
gettext_noop("Automatic log file rotation will occur after N minutes."),
static bool
check_maxconnections(int *newval, void **extra, GucSource source)
{
- if (*newval + GetNumShmemAttachedBgworkers() + autovacuum_max_workers + 1 >
- MAX_BACKENDS)
+ if (*newval + autovacuum_max_workers + 1 +
+ max_worker_processes > MAX_BACKENDS)
return false;
return true;
}
@@ -8676,8 +8689,15 @@ check_maxconnections(int *newval, void **extra, GucSource source)
static bool
check_autovacuum_max_workers(int *newval, void **extra, GucSource source)
{
- if (MaxConnections + *newval + 1 + GetNumShmemAttachedBgworkers() >
- MAX_BACKENDS)
+ if (MaxConnections + *newval + 1 + max_worker_processes > MAX_BACKENDS)
+ return false;
+ return true;
+}
+
+static bool
+check_max_worker_processes(int *newval, void **extra, GucSource source)
+{
+ if (MaxConnections + autovacuum_max_workers + 1 + *newval > MAX_BACKENDS)
return false;
return true;
}
index 0d7249f4dbd7421d1184cbfaffb9d384071da5fe..d69a02be87f7ffdc8e0715c379ba7e0c5fa78376 100644 (file)
# - Asynchronous Behavior -
#effective_io_concurrency = 1 # 1-1000; 0 disables prefetching
+#max_worker_processes = 8
#------------------------------------------------------------------------------
index a790f99cb51d3649d8bbd2f32ab0065470bccda8..fde483a616ab4092d05eb0a1c0ac7b981c4b2458 100644 (file)
wal_level_str(ControlFile.wal_level));
printf(_("Current max_connections setting: %d\n"),
ControlFile.MaxConnections);
+ printf(_("Current max_worker_processes setting: %d\n"),
+ ControlFile.max_worker_processes);
printf(_("Current max_prepared_xacts setting: %d\n"),
ControlFile.max_prepared_xacts);
printf(_("Current max_locks_per_xact setting: %d\n"),
index 6d3e9f5439f652f1ddac73c0c5b4d86bc7d571c7..465905c8503126037930450a4b34bc31020752be 100644 (file)
ControlFile.wal_level = WAL_LEVEL_MINIMAL;
ControlFile.MaxConnections = 100;
+ ControlFile.max_worker_processes = 8;
ControlFile.max_prepared_xacts = 0;
ControlFile.max_locks_per_xact = 64;
*/
ControlFile.wal_level = WAL_LEVEL_MINIMAL;
ControlFile.MaxConnections = 100;
+ ControlFile.max_worker_processes = 8;
ControlFile.max_prepared_xacts = 0;
ControlFile.max_locks_per_xact = 64;
index ee12d1a110a2a55db98e7efaa6a232238deb4ade..c3e173106fc032479d103f94c6bf76df5b3be109 100644 (file)
/*
* Each page of XLOG file has a header like this:
*/
-#define XLOG_PAGE_MAGIC 0xD075 /* can be used as WAL version indicator */
+#define XLOG_PAGE_MAGIC 0xD076 /* can be used as WAL version indicator */
typedef struct XLogPageHeaderData
{
@@ -205,6 +205,7 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader;
typedef struct xl_parameter_change
{
int MaxConnections;
+ int max_worker_processes;
int max_prepared_xacts;
int max_locks_per_xact;
int wal_level;
index 0e297610d8a526847b260ea31db28f54056a1023..637221e6347c1e673a24675176dce751caa9d872 100644 (file)
*/
int wal_level;
int MaxConnections;
+ int max_worker_processes;
int max_prepared_xacts;
int max_locks_per_xact;
index be3add95dcaa4bc5bd98451651d1b6bea125139d..48985b370fa6fe8916c16ec66b346765cdc92b0c 100644 (file)
extern PGDLLIMPORT int NBuffers;
extern int MaxBackends;
extern int MaxConnections;
+extern int max_worker_processes;
extern PGDLLIMPORT int MyProcPid;
extern PGDLLIMPORT pg_time_t MyStartTime;