summaryrefslogtreecommitdiff
path: root/src/backend/postmaster/postmaster.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/postmaster/postmaster.c')
-rw-r--r--src/backend/postmaster/postmaster.c227
1 files changed, 49 insertions, 178 deletions
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 496192d57c..d9b800c4e7 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -103,7 +103,7 @@
#include "miscadmin.h"
#include "pgstat.h"
#include "postmaster/autovacuum.h"
-#include "postmaster/bgworker.h"
+#include "postmaster/bgworker_internals.h"
#include "postmaster/fork_process.h"
#include "postmaster/pgarch.h"
#include "postmaster/postmaster.h"
@@ -117,6 +117,7 @@
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
#include "utils/datetime.h"
+#include "utils/dynamic_loader.h"
#include "utils/memutils.h"
#include "utils/ps_status.h"
#include "utils/timeout.h"
@@ -178,29 +179,6 @@ static dlist_head BackendList = DLIST_STATIC_INIT(BackendList);
static Backend *ShmemBackendArray;
#endif
-
-/*
- * List of background workers.
- *
- * A worker that requests a database connection during registration will have
- * rw_backend set, and will be present in BackendList. Note: do not rely on
- * rw_backend being non-NULL for shmem-connected workers!
- */
-typedef struct RegisteredBgWorker
-{
- BackgroundWorker rw_worker; /* its registry entry */
- Backend *rw_backend; /* its BackendList entry, or NULL */
- pid_t rw_pid; /* 0 if not running */
- int rw_child_slot;
- TimestampTz rw_crashed_at; /* if not 0, time it last crashed */
-#ifdef EXEC_BACKEND
- int rw_cookie;
-#endif
- slist_node rw_lnode; /* list link */
-} RegisteredBgWorker;
-
-static slist_head BackgroundWorkerList = SLIST_STATIC_INIT(BackgroundWorkerList);
-
BackgroundWorker *MyBgworkerEntry = NULL;
@@ -532,8 +510,6 @@ static bool save_backend_variables(BackendParameters *param, Port *port,
static void ShmemBackendArrayAdd(Backend *bn);
static void ShmemBackendArrayRemove(Backend *bn);
-
-static BackgroundWorker *find_bgworker_entry(int cookie);
#endif /* EXEC_BACKEND */
#define StartupDataBase() StartChildProcess(StartupProcess)
@@ -1456,7 +1432,7 @@ DetermineSleepTime(struct timeval * timeout)
if (HaveCrashedWorker)
{
- slist_iter siter;
+ slist_mutable_iter siter;
/*
* When there are crashed bgworkers, we sleep just long enough that
@@ -1464,7 +1440,7 @@ DetermineSleepTime(struct timeval * timeout)
* determine the minimum of all wakeup times according to most recent
* crash time and requested restart interval.
*/
- slist_foreach(siter, &BackgroundWorkerList)
+ slist_foreach_modify(siter, &BackgroundWorkerList)
{
RegisteredBgWorker *rw;
TimestampTz this_wakeup;
@@ -1475,7 +1451,10 @@ DetermineSleepTime(struct timeval * timeout)
continue;
if (rw->rw_worker.bgw_restart_time == BGW_NEVER_RESTART)
+ {
+ ForgetBackgroundWorker(rw);
continue;
+ }
this_wakeup = TimestampTzPlusMilliseconds(rw->rw_crashed_at,
1000L * rw->rw_worker.bgw_restart_time);
@@ -4619,7 +4598,7 @@ SubPostmasterMain(int argc, char *argv[])
}
if (strncmp(argv[1], "--forkbgworker=", 15) == 0)
{
- int cookie;
+ int shmem_slot;
/* Close the postmaster's sockets */
ClosePostmasterPorts(false);
@@ -4633,8 +4612,8 @@ SubPostmasterMain(int argc, char *argv[])
/* Attach process to shared data structures */
CreateSharedMemoryAndSemaphores(false, 0);
- cookie = atoi(argv[1] + 15);
- MyBgworkerEntry = find_bgworker_entry(cookie);
+ shmem_slot = atoi(argv[1] + 15);
+ MyBgworkerEntry = BackgroundWorkerEntry(shmem_slot);
do_start_bgworker();
}
if (strcmp(argv[1], "--forkarch") == 0)
@@ -4697,9 +4676,17 @@ static void
sigusr1_handler(SIGNAL_ARGS)
{
int save_errno = errno;
+ bool start_bgworker = false;
PG_SETMASK(&BlockSig);
+ /* Process background worker state change. */
+ if (CheckPostmasterSignal(PMSIGNAL_BACKGROUND_WORKER_CHANGE))
+ {
+ BackgroundWorkerStateChange();
+ start_bgworker = true;
+ }
+
/*
* RECOVERY_STARTED and BEGIN_HOT_STANDBY signals are ignored in
* unexpected states. If the startup process quickly starts up, completes
@@ -4737,11 +4724,13 @@ sigusr1_handler(SIGNAL_ARGS)
(errmsg("database system is ready to accept read only connections")));
pmState = PM_HOT_STANDBY;
-
/* Some workers may be scheduled to start now */
- StartOneBackgroundWorker();
+ start_bgworker = true;
}
+ if (start_bgworker)
+ StartOneBackgroundWorker();
+
if (CheckPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER) &&
PgArchPID != 0)
{
@@ -5215,126 +5204,6 @@ MaxLivePostmasterChildren(void)
}
/*
- * Register a new background worker.
- *
- * This can only be called in the _PG_init function of a module library
- * that's loaded by shared_preload_libraries; otherwise it has no effect.
- */
-void
-RegisterBackgroundWorker(BackgroundWorker *worker)
-{
- RegisteredBgWorker *rw;
- int namelen = strlen(worker->bgw_name);
- static int numworkers = 0;
-
-#ifdef EXEC_BACKEND
-
- /*
- * Use 1 here, not 0, to avoid confusing a possible bogus cookie read by
- * atoi() in SubPostmasterMain.
- */
- static int BackgroundWorkerCookie = 1;
-#endif
-
- if (!IsUnderPostmaster)
- ereport(LOG,
- (errmsg("registering background worker: %s", worker->bgw_name)));
-
- if (!process_shared_preload_libraries_in_progress)
- {
- if (!IsUnderPostmaster)
- ereport(LOG,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("background worker \"%s\": must be registered in shared_preload_libraries",
- worker->bgw_name)));
- return;
- }
-
- /* sanity check for flags */
- if (worker->bgw_flags & BGWORKER_BACKEND_DATABASE_CONNECTION)
- {
- if (!(worker->bgw_flags & BGWORKER_SHMEM_ACCESS))
- {
- if (!IsUnderPostmaster)
- ereport(LOG,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("background worker \"%s\": must attach to shared memory in order to request a database connection",
- worker->bgw_name)));
- return;
- }
-
- if (worker->bgw_start_time == BgWorkerStart_PostmasterStart)
- {
- if (!IsUnderPostmaster)
- ereport(LOG,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("background worker \"%s\": cannot request database access if starting at postmaster start",
- worker->bgw_name)));
- return;
- }
-
- /* XXX other checks? */
- }
-
- if ((worker->bgw_restart_time < 0 &&
- worker->bgw_restart_time != BGW_NEVER_RESTART) ||
- (worker->bgw_restart_time > USECS_PER_DAY / 1000))
- {
- if (!IsUnderPostmaster)
- ereport(LOG,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("background worker \"%s\": invalid restart interval",
- worker->bgw_name)));
- return;
- }
-
- /*
- * 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. For now, it doesn't seem
- * important to relax this restriction.
- */
- if (++numworkers > max_worker_processes)
- {
- ereport(LOG,
- (errcode(ERRCODE_CONFIGURATION_LIMIT_EXCEEDED),
- errmsg("too many background workers"),
- errdetail_plural("Up to %d background worker can be registered with the current settings.",
- "Up to %d background workers can be registered with the current settings.",
- max_worker_processes,
- max_worker_processes),
- errhint("Consider increasing the configuration parameter \"max_worker_processes\".")));
- return;
- }
-
- /*
- * Copy the registration data into the registered workers list.
- */
- rw = malloc(sizeof(RegisteredBgWorker) + namelen + 1);
- if (rw == NULL)
- {
- ereport(LOG,
- (errcode(ERRCODE_OUT_OF_MEMORY),
- errmsg("out of memory")));
- return;
- }
-
- rw->rw_worker = *worker;
- rw->rw_worker.bgw_name = ((char *) rw) + sizeof(RegisteredBgWorker);
- strlcpy(rw->rw_worker.bgw_name, worker->bgw_name, namelen + 1);
-
- rw->rw_backend = NULL;
- rw->rw_pid = 0;
- rw->rw_child_slot = 0;
- rw->rw_crashed_at = 0;
-#ifdef EXEC_BACKEND
- rw->rw_cookie = BackgroundWorkerCookie++;
-#endif
-
- slist_push_head(&BackgroundWorkerList, &rw->rw_lnode);
-}
-
-/*
* Connect background worker to a database.
*/
void
@@ -5372,25 +5241,6 @@ BackgroundWorkerUnblockSignals(void)
PG_SETMASK(&UnBlockSig);
}
-#ifdef EXEC_BACKEND
-static BackgroundWorker *
-find_bgworker_entry(int cookie)
-{
- slist_iter iter;
-
- slist_foreach(iter, &BackgroundWorkerList)
- {
- RegisteredBgWorker *rw;
-
- rw = slist_container(RegisteredBgWorker, rw_lnode, iter.cur);
- if (rw->rw_cookie == cookie)
- return &rw->rw_worker;
- }
-
- return NULL;
-}
-#endif
-
static void
bgworker_quickdie(SIGNAL_ARGS)
{
@@ -5453,6 +5303,7 @@ do_start_bgworker(void)
sigjmp_buf local_sigjmp_buf;
char buf[MAXPGPATH];
BackgroundWorker *worker = MyBgworkerEntry;
+ bgworker_main_type entrypt;
if (worker == NULL)
elog(FATAL, "unable to find bgworker entry");
@@ -5569,6 +5420,23 @@ do_start_bgworker(void)
#endif
/*
+ * If bgw_main is set, we use that value as the initial entrypoint.
+ * However, if the library containing the entrypoint wasn't loaded at
+ * postmaster startup time, passing it as a direct function pointer is
+ * not possible. To work around that, we allow callers for whom a
+ * function pointer is not available to pass a library name (which will
+ * be loaded, if necessary) and a function name (which will be looked up
+ * in the named library).
+ */
+ if (worker->bgw_main != NULL)
+ entrypt = worker->bgw_main;
+ else
+ entrypt = (bgworker_main_type)
+ load_external_function(worker->bgw_library_name,
+ worker->bgw_function_name,
+ true, NULL);
+
+ /*
* Note that in normal processes, we would call InitPostgres here. For a
* worker, however, we don't know what database to connect to, yet; so we
* need to wait until the user code does it via
@@ -5578,7 +5446,7 @@ do_start_bgworker(void)
/*
* Now invoke the user-defined worker code
*/
- worker->bgw_main(worker->bgw_main_arg);
+ entrypt(worker->bgw_main_arg);
/* ... and if it returns, we're done */
proc_exit(0);
@@ -5586,13 +5454,13 @@ do_start_bgworker(void)
#ifdef EXEC_BACKEND
static pid_t
-bgworker_forkexec(int cookie)
+bgworker_forkexec(int shmem_slot)
{
char *av[10];
int ac = 0;
char forkav[MAXPGPATH];
- snprintf(forkav, MAXPGPATH, "--forkbgworker=%d", cookie);
+ snprintf(forkav, MAXPGPATH, "--forkbgworker=%d", shmem_slot);
av[ac++] = "postgres";
av[ac++] = forkav;
@@ -5621,7 +5489,7 @@ start_bgworker(RegisteredBgWorker *rw)
rw->rw_worker.bgw_name)));
#ifdef EXEC_BACKEND
- switch ((worker_pid = bgworker_forkexec(rw->rw_cookie)))
+ switch ((worker_pid = bgworker_forkexec(rw->rw_shmem_slot)))
#else
switch ((worker_pid = fork_process()))
#endif
@@ -5749,7 +5617,7 @@ assign_backendlist_entry(RegisteredBgWorker *rw)
static void
StartOneBackgroundWorker(void)
{
- slist_iter iter;
+ slist_mutable_iter iter;
TimestampTz now = 0;
if (FatalError)
@@ -5761,7 +5629,7 @@ StartOneBackgroundWorker(void)
HaveCrashedWorker = false;
- slist_foreach(iter, &BackgroundWorkerList)
+ slist_foreach_modify(iter, &BackgroundWorkerList)
{
RegisteredBgWorker *rw;
@@ -5781,7 +5649,10 @@ StartOneBackgroundWorker(void)
if (rw->rw_crashed_at != 0)
{
if (rw->rw_worker.bgw_restart_time == BGW_NEVER_RESTART)
+ {
+ ForgetBackgroundWorker(rw);
continue;
+ }
if (now == 0)
now = GetCurrentTimestamp();