Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit523beaa

Browse files
committed
Provide a reliable mechanism for terminating a background worker.
Although previously-introduced APIs allow the process that registers abackground worker to obtain the worker's PID, there's no way to preventa worker that is not currently running from being restarted. Thispatch introduces a new API TerminateBackgroundWorker() that preventsthe background worker from being restarted, terminates it if it iscurrently running, and causes it to be unregistered if or when it isnot running.Patch by me. Review by Michael Paquier and KaiGai Kohei.
1 parentc2316dc commit523beaa

File tree

5 files changed

+96
-19
lines changed

5 files changed

+96
-19
lines changed

‎doc/src/sgml/bgworker.sgml

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -184,13 +184,18 @@ typedef struct BackgroundWorker
184184
argument to <function>RegisterDynamicBackgroundWorker</function>. If the
185185
worker is successfully registered, this pointer will be initialized with an
186186
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.
187+
<function>GetBackgroundWorkerPid(<parameter>BackgroundWorkerHandle *</parameter>, <parameter>pid_t *</parameter>)</function> or
188+
<function>TerminateBackgroundWorker(<parameter>BackgroundWorkerHandle *</parameter>)</function>.
189+
<function>GetBackgroundWorker</> can be used to poll the status of the
190+
worker: a return value of <literal>BGWH_NOT_YET_STARTED</> indicates that
191+
the worker has not yet been started by the postmaster;
192+
<literal>BGWH_STOPPED</literal> indicates that it has been started but is
193+
no longer running; and <literal>BGWH_STARTED</literal> indicates that it is
194+
currently running. In this last case, the PID will also be returned via the
195+
second argument.
196+
<function>TerminateBackgroundWorker</> causes the postmaster to send
197+
<literal>SIGTERM</> to the worker if it is running, and to unregister it
198+
as soon as it is not.
194199
</para>
195200

196201
<para>

‎src/backend/postmaster/bgworker.c

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ slist_head BackgroundWorkerList = SLIST_STATIC_INIT(BackgroundWorkerList);
5555
* must fully initialize the slot - and insert a write memory barrier - before
5656
* marking it as in use.
5757
*
58+
* As an exception, however, even when the slot is in use, regular backends
59+
* may set the 'terminate' flag for a slot, telling the postmaster not
60+
* to restart it. Once the background worker is no longer running, the slot
61+
* will be released for reuse.
62+
*
5863
* In addition to coordinating with the postmaster, backends modifying this
5964
* data structure must coordinate with each other. Since they can take locks,
6065
* this is straightforward: any backend wishing to manipulate a slot must
@@ -67,6 +72,7 @@ slist_head BackgroundWorkerList = SLIST_STATIC_INIT(BackgroundWorkerList);
6772
typedefstructBackgroundWorkerSlot
6873
{
6974
boolin_use;
75+
boolterminate;
7076
pid_tpid;/* InvalidPid = not started yet; 0 = dead */
7177
uint64generation;/* incremented when slot is recycled */
7278
BackgroundWorkerworker;
@@ -134,6 +140,7 @@ BackgroundWorkerShmemInit(void)
134140
rw=slist_container(RegisteredBgWorker,rw_lnode,siter.cur);
135141
Assert(slotno<max_worker_processes);
136142
slot->in_use= true;
143+
slot->terminate= false;
137144
slot->pid=InvalidPid;
138145
slot->generation=0;
139146
rw->rw_shmem_slot=slotno;
@@ -223,14 +230,29 @@ BackgroundWorkerStateChange(void)
223230
*/
224231
pg_read_barrier();
225232

226-
/*
227-
* See whether we already know about this worker. If not, we need
228-
* to update our backend-private BackgroundWorkerList to match shared
229-
* memory.
230-
*/
233+
/* See whether we already know about this worker. */
231234
rw=FindRegisteredWorkerBySlotNumber(slotno);
232235
if (rw!=NULL)
236+
{
237+
/*
238+
* In general, the worker data can't change after it's initially
239+
* registered. However, someone can set the terminate flag.
240+
*/
241+
if (slot->terminate&& !rw->rw_terminate)
242+
{
243+
rw->rw_terminate= true;
244+
if (rw->rw_pid!=0)
245+
kill(rw->rw_pid,SIGTERM);
246+
}
233247
continue;
248+
}
249+
250+
/* If it's already flagged as do not restart, just release the slot. */
251+
if (slot->terminate)
252+
{
253+
slot->in_use= false;
254+
continue;
255+
}
234256

235257
/*
236258
* Copy the registration data into the registered workers list.
@@ -292,6 +314,7 @@ BackgroundWorkerStateChange(void)
292314
rw->rw_child_slot=0;
293315
rw->rw_crashed_at=0;
294316
rw->rw_shmem_slot=slotno;
317+
rw->rw_terminate= false;
295318

296319
/* Log it! */
297320
ereport(LOG,
@@ -714,6 +737,7 @@ RegisterBackgroundWorker(BackgroundWorker *worker)
714737
rw->rw_pid=0;
715738
rw->rw_child_slot=0;
716739
rw->rw_crashed_at=0;
740+
rw->rw_terminate= false;
717741

718742
slist_push_head(&BackgroundWorkerList,&rw->rw_lnode);
719743
}
@@ -764,6 +788,7 @@ RegisterDynamicBackgroundWorker(BackgroundWorker *worker,
764788
memcpy(&slot->worker,worker,sizeof(BackgroundWorker));
765789
slot->pid=InvalidPid;/* indicates not started yet */
766790
slot->generation++;
791+
slot->terminate= false;
767792
generation=slot->generation;
768793

769794
/*
@@ -905,3 +930,33 @@ WaitForBackgroundWorkerStartup(BackgroundWorkerHandle *handle, pid_t *pidp)
905930
set_latch_on_sigusr1=save_set_latch_on_sigusr1;
906931
returnstatus;
907932
}
933+
934+
/*
935+
* Instruct the postmaster to terminate a background worker.
936+
*
937+
* Note that it's safe to do this without regard to whether the worker is
938+
* still running, or even if the worker may already have existed and been
939+
* unregistered.
940+
*/
941+
void
942+
TerminateBackgroundWorker(BackgroundWorkerHandle*handle)
943+
{
944+
BackgroundWorkerSlot*slot;
945+
boolsignal_postmaster= false;
946+
947+
Assert(handle->slot<max_worker_processes);
948+
slot=&BackgroundWorkerData->slot[handle->slot];
949+
950+
/* Set terminate flag in shared memory, unless slot has been reused. */
951+
LWLockAcquire(BackgroundWorkerLock,LW_EXCLUSIVE);
952+
if (handle->generation==slot->generation)
953+
{
954+
slot->terminate= true;
955+
signal_postmaster= true;
956+
}
957+
LWLockRelease(BackgroundWorkerLock);
958+
959+
/* Make sure the postmaster notices the change to shared memory. */
960+
if (signal_postmaster)
961+
SendPostmasterSignal(PMSIGNAL_BACKGROUND_WORKER_CHANGE);
962+
}

‎src/backend/postmaster/postmaster.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1463,7 +1463,8 @@ DetermineSleepTime(struct timeval * timeout)
14631463
if (rw->rw_crashed_at==0)
14641464
continue;
14651465

1466-
if (rw->rw_worker.bgw_restart_time==BGW_NEVER_RESTART)
1466+
if (rw->rw_worker.bgw_restart_time==BGW_NEVER_RESTART
1467+
||rw->rw_terminate)
14671468
{
14681469
ForgetBackgroundWorker(&siter);
14691470
continue;
@@ -5471,6 +5472,13 @@ maybe_start_bgworker(void)
54715472
if (rw->rw_pid!=0)
54725473
continue;
54735474

5475+
/* marked for death? */
5476+
if (rw->rw_terminate)
5477+
{
5478+
ForgetBackgroundWorker(&iter);
5479+
continue;
5480+
}
5481+
54745482
/*
54755483
* If this worker has crashed previously, maybe it needs to be
54765484
* restarted (unless on registration it specified it doesn't want to

‎src/include/postmaster/bgworker.h

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,22 @@
99
* worker.Workers can also be registered dynamically at runtime. In either
1010
* case, the worker process is forked from the postmaster and runs the
1111
* user-supplied "main" function. This code may connect to a database and
12-
* run transactions. Once started, it stays active until shutdown or crash;
13-
* unless the restart interval is declared as BGW_NEVER_RESTART and the
14-
* process exits with a return code of 1; workers that do this are
15-
* automatically unregistered by the postmaster.
12+
* run transactions. Workers can remain active indefinitely, but will be
13+
* terminated if a shutdown or crash occurs.
1614
*
1715
* If the fork() call fails in the postmaster, it will try again later. Note
1816
* that the failure can only be transient (fork failure due to high load,
1917
* memory pressure, too many processes, etc); more permanent problems, like
2018
* failure to connect to a database, are detected later in the worker and dealt
21-
* with just by having the worker exit normally. Postmaster will launch a new
22-
* worker again later.
19+
* with just by having the worker exit normally. A worker which exits with a
20+
* return code of 0 will be immediately restarted by the postmaster. A worker
21+
* which exits with a return code of 1 will be restarted after the configured
22+
* restart interval, or never if that interval is set to BGW_NEVER_RESTART.
23+
* The TerminateBackgroundWorker() function can be used to terminate a
24+
* dynamically registered background worker; the worker will be sent a SIGTERM
25+
* and will not be restarted after it exits. Whenever the postmaster knows
26+
* that a worker will not be restarted, it unregisters the worker, freeing up
27+
* that worker's slot for use by a new worker.
2328
*
2429
* Note that there might be more than one worker in a database concurrently,
2530
* and the same module may request more than one worker running the same (or
@@ -107,6 +112,9 @@ extern BgwHandleStatus GetBackgroundWorkerPid(BackgroundWorkerHandle *handle,
107112
externBgwHandleStatusWaitForBackgroundWorkerStartup(BackgroundWorkerHandle*
108113
handle,pid_t*pid);
109114

115+
/* Terminate a bgworker */
116+
externvoidTerminateBackgroundWorker(BackgroundWorkerHandle*handle);
117+
110118
/* This is valid in a running worker */
111119
externBackgroundWorker*MyBgworkerEntry;
112120

‎src/include/postmaster/bgworker_internals.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ typedef struct RegisteredBgWorker
3131
intrw_child_slot;
3232
TimestampTzrw_crashed_at;/* if not 0, time it last crashed */
3333
intrw_shmem_slot;
34+
boolrw_terminate;
3435
slist_noderw_lnode;/* list link */
3536
}RegisteredBgWorker;
3637

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp