Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 090d0f2

Browse files
committed
Allow discovery of whether a dynamic background worker is running.
Using the infrastructure provided by this patch, it's possible either to wait for the startup of a dynamically-registered background worker, or to poll the status of such a worker without waiting. In either case, the current PID of the worker process can also be obtained. As usual, worker_spi is updated to demonstrate the new functionality. Patch by me. Review by Andres Freund.
1 parent c9e2e2d commit 090d0f2

File tree

12 files changed

+368
-13
lines changed

12 files changed

+368
-13
lines changed

contrib/worker_spi/worker_spi--1.0.sql

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44
\echo Use "CREATE EXTENSION worker_spi" to load this file. \quit
55

66
CREATE FUNCTION worker_spi_launch(pg_catalog.int4)
7-
RETURNS pg_catalog.bool STRICT
7+
RETURNS pg_catalog.int4 STRICT
88
AS 'MODULE_PATHNAME'
99
LANGUAGE C;

contrib/worker_spi/worker_spi.c

+24-2
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,9 @@ worker_spi_launch(PG_FUNCTION_ARGS)
365365
{
366366
int32 i = PG_GETARG_INT32(0);
367367
BackgroundWorker worker;
368+
BackgroundWorkerHandle *handle;
369+
BgwHandleStatus status;
370+
pid_t pid;
368371

369372
worker.bgw_flags = BGWORKER_SHMEM_ACCESS |
370373
BGWORKER_BACKEND_DATABASE_CONNECTION;
@@ -375,6 +378,25 @@ worker_spi_launch(PG_FUNCTION_ARGS)
375378
sprintf(worker.bgw_function_name, "worker_spi_main");
376379
snprintf(worker.bgw_name, BGW_MAXLEN, "worker %d", i);
377380
worker.bgw_main_arg = Int32GetDatum(i);
378-
379-
PG_RETURN_BOOL(RegisterDynamicBackgroundWorker(&worker));
381+
/* set bgw_notify_pid so that we can use WaitForBackgroundWorkerStartup */
382+
worker.bgw_notify_pid = MyProcPid;
383+
384+
if (!RegisterDynamicBackgroundWorker(&worker, &handle))
385+
PG_RETURN_NULL();
386+
387+
status = WaitForBackgroundWorkerStartup(handle, &pid);
388+
389+
if (status == BGWH_STOPPED)
390+
ereport(ERROR,
391+
(errcode(ERRCODE_INSUFFICIENT_RESOURCES),
392+
errmsg("could not start background process"),
393+
errhint("More details may be available in the server log.")));
394+
if (status == BGWH_POSTMASTER_DIED)
395+
ereport(ERROR,
396+
(errcode(ERRCODE_INSUFFICIENT_RESOURCES),
397+
errmsg("cannot start background processes without postmaster"),
398+
errhint("Kill all remaining database processes and restart the database.")));
399+
Assert(status == BGWH_STARTED);
400+
401+
PG_RETURN_INT32(pid);
380402
}

doc/src/sgml/bgworker.sgml

+49-5
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@
3737
<function>RegisterBackgroundWorker(<type>BackgroundWorker *worker</type>)</function>
3838
from its <function>_PG_init()</>. Background workers can also be started
3939
after the system is up and running by calling the function
40-
<function>RegisterDynamicBackgroundWorker</function>(<type>BackgroundWorker
41-
*worker</type>). Unlike <function>RegisterBackgroundWorker</>, which can
42-
only be called from within the postmaster,
43-
<function>RegisterDynamicBackgroundWorker</function> must be called from
44-
a regular backend.
40+
<function>RegisterDynamicBackgroundWorker(<type>BackgroundWorker
41+
*worker, BackgroundWorkerHandle **handle</type>)</function>. Unlike
42+
<function>RegisterBackgroundWorker</>, which can only be called from within
43+
the postmaster, <function>RegisterDynamicBackgroundWorker</function> must be
44+
called from a regular backend.
4545
</para>
4646

4747
<para>
@@ -58,6 +58,7 @@ typedef struct BackgroundWorker
5858
char bgw_library_name[BGW_MAXLEN]; /* only if bgw_main is NULL */
5959
char bgw_function_name[BGW_MAXLEN]; /* only if bgw_main is NULL */
6060
Datum bgw_main_arg;
61+
int bgw_notify_pid;
6162
} BackgroundWorker;
6263
</programlisting>
6364
</para>
@@ -135,6 +136,15 @@ typedef struct BackgroundWorker
135136
<structfield>bgw_main</structfield> is NULL.
136137
</para>
137138

139+
<para>
140+
<structfield>bgw_notify_pid</structfield> is the PID of a PostgreSQL
141+
backend process to which the postmaster should send <literal>SIGUSR1</>
142+
when the process is started or exits. It should be 0 for workers registered
143+
at postmaster startup time, or when the backend registering the worker does
144+
not wish to wait for the worker to start up. Otherwise, it should be
145+
initialized to <literal>MyProcPid</>.
146+
</para>
147+
138148
<para>Once running, the process can connect to a database by calling
139149
<function>BackgroundWorkerInitializeConnection(<parameter>char *dbname</parameter>, <parameter>char *username</parameter>)</function>.
140150
This allows the process to run transactions and queries using the
@@ -165,6 +175,40 @@ typedef struct BackgroundWorker
165175
<command>postgres</> itself has terminated.
166176
</para>
167177

178+
<para>
179+
When a background worker is registered using the
180+
<function>RegisterDynamicBackgroundWorker</function> function, it is
181+
possible for the backend performing the registration to obtain information
182+
the status of the worker. Backends wishing to do this should pass the
183+
address of a <type>BackgroundWorkerHandle *</type> as the second argument
184+
to <function>RegisterDynamicBackgroundWorker</function>. If the worker
185+
is successfully registered, this pointer will be initialized with an
186+
opaque handle that can subsequently be passed to
187+
<function>GetBackgroundWorkerPid(<parameter>BackgroundWorkerHandle *</parameter>, <parameter>pid_t *</parameter>)</function>.
188+
This function can be used to poll the status of the worker: a return
189+
value of <literal>BGWH_NOT_YET_STARTED</> indicates that the worker has not
190+
yet been started by the postmaster; <literal>BGWH_STOPPED</literal>
191+
indicates that it has been started but is no longer running; and
192+
<literal>BGWH_STARTED</literal> indicates that it is currently running.
193+
In this last case, the PID will also be returned via the second argument.
194+
</para>
195+
196+
<para>
197+
In some cases, a process which registers a background worker may wish to
198+
wait for the worker to start up. This can be accomplished by initializing
199+
<structfield>bgw_notify_pid</structfield> to <literal>MyProcPid</> and
200+
then passing the <type>BackgroundWorkerHandle *</type> obtained at
201+
registration time to
202+
<function>WaitForBackgroundWorkerStartup(<parameter>BackgroundWorkerHandle
203+
*handle</parameter>, <parameter>pid_t *</parameter>)</function> function.
204+
This function will block until the postmaster has attempted to start the
205+
background worker, or until the postmaster dies. If the background runner
206+
is running, the return value will <literal>BGWH_STARTED</>, and
207+
the PID will be written to the provided address. Otherwise, the return
208+
value will be <literal>BGWH_STOPPED</literal> or
209+
<literal>BGWH_POSTMASTER_DIED</literal>.
210+
</para>
211+
168212
<para>
169213
The <filename>worker_spi</> contrib module contains a working example,
170214
which demonstrates some useful techniques.

src/backend/commands/async.c

-2
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,6 @@ typedef struct QueueBackendStatus
207207
QueuePosition pos; /* backend has read queue up to here */
208208
} QueueBackendStatus;
209209

210-
#define InvalidPid (-1)
211-
212210
/*
213211
* Shared memory state for LISTEN/NOTIFY (excluding its SLRU stuff)
214212
*

0 commit comments

Comments
 (0)