Skip to content

Commit c98605c

Browse files
committed
Pass extra data to bgworkers, and use this to fix parallel contexts.
Up until now, the total amount of data that could be passed to a background worker at startup was one datum, which can be a small as 4 bytes on some systems. That's enough to pass a dsm_handle or an array index, but not much else. Add a bgw_extra flag to the BackgroundWorker struct, allowing up to 128 bytes to be passed to a new worker on any platform. Use this to fix a problem I recently discovered with the parallel context machinery added in 9.5: the master assigns each worker an array index, and each worker subsequently assigns itself an array index, and there's nothing to guarantee that the two sets of indexes match, leading to chaos. Normally, I would not back-patch the change to add bgw_extra, since it is basically a feature addition. However, since 9.5 is still in beta and there seems to be no other sensible way to repair the broken parallel context machinery, back-patch to 9.5. Existing background worker code can ignore the bgw_extra field without a problem, but might need to be recompiled since the structure size has changed. Report and patch by me. Review by Amit Kapila.
1 parent 1d97b25 commit c98605c

File tree

4 files changed

+18
-16
lines changed

4 files changed

+18
-16
lines changed

doc/src/sgml/bgworker.sgml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
char bgw_extra[BGW_EXTRALEN];
6162
int bgw_notify_pid;
6263
} BackgroundWorker;
6364
</programlisting>
@@ -136,6 +137,13 @@ typedef struct BackgroundWorker
136137
<structfield>bgw_main</structfield> is NULL.
137138
</para>
138139

140+
<para>
141+
<structfield>bgw_extra</structfield> can contain extra data to be passed
142+
to the background worker. Unlike <structfield>bgw_main_arg</>, this data
143+
is not passed as an argument to the worker's main function, but it can be
144+
accessed via <literal>MyBgworkerEntry</literal>, as discussed above.
145+
</para>
146+
139147
<para>
140148
<structfield>bgw_notify_pid</structfield> is the PID of a PostgreSQL
141149
backend process to which the postmaster should send <literal>SIGUSR1</>

src/backend/access/transam/parallel.c

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,6 @@ typedef struct FixedParallelState
7777
/* Mutex protects remaining fields. */
7878
slock_t mutex;
7979

80-
/* Track whether workers have attached. */
81-
int workers_expected;
82-
int workers_attached;
83-
8480
/* Maximum XactLastRecEnd of any worker. */
8581
XLogRecPtr last_xlog_end;
8682
} FixedParallelState;
@@ -286,8 +282,6 @@ InitializeParallelDSM(ParallelContext *pcxt)
286282
fps->parallel_master_backend_id = MyBackendId;
287283
fps->entrypoint = pcxt->entrypoint;
288284
SpinLockInit(&fps->mutex);
289-
fps->workers_expected = pcxt->nworkers;
290-
fps->workers_attached = 0;
291285
fps->last_xlog_end = 0;
292286
shm_toc_insert(pcxt->toc, PARALLEL_KEY_FIXED, fps);
293287

@@ -406,6 +400,7 @@ LaunchParallelWorkers(ParallelContext *pcxt)
406400
worker.bgw_main = ParallelWorkerMain;
407401
worker.bgw_main_arg = UInt32GetDatum(dsm_segment_handle(pcxt->seg));
408402
worker.bgw_notify_pid = MyProcPid;
403+
memset(&worker.bgw_extra, 0, BGW_EXTRALEN);
409404

410405
/*
411406
* Start workers.
@@ -417,6 +412,7 @@ LaunchParallelWorkers(ParallelContext *pcxt)
417412
*/
418413
for (i = 0; i < pcxt->nworkers; ++i)
419414
{
415+
memcpy(worker.bgw_extra, &i, sizeof(int));
420416
if (!any_registrations_failed &&
421417
RegisterDynamicBackgroundWorker(&worker,
422418
&pcxt->worker[i].bgwhandle))
@@ -825,6 +821,10 @@ ParallelWorkerMain(Datum main_arg)
825821
pqsignal(SIGTERM, die);
826822
BackgroundWorkerUnblockSignals();
827823

824+
/* Determine and set our parallel worker number. */
825+
Assert(ParallelWorkerNumber == -1);
826+
memcpy(&ParallelWorkerNumber, MyBgworkerEntry->bgw_extra, sizeof(int));
827+
828828
/* Set up a memory context and resource owner. */
829829
Assert(CurrentResourceOwner == NULL);
830830
CurrentResourceOwner = ResourceOwnerCreate(NULL, "parallel toplevel");
@@ -849,18 +849,9 @@ ParallelWorkerMain(Datum main_arg)
849849
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
850850
errmsg("bad magic number in dynamic shared memory segment")));
851851

852-
/* Determine and set our worker number. */
852+
/* Look up fixed parallel state. */
853853
fps = shm_toc_lookup(toc, PARALLEL_KEY_FIXED);
854854
Assert(fps != NULL);
855-
Assert(ParallelWorkerNumber == -1);
856-
SpinLockAcquire(&fps->mutex);
857-
if (fps->workers_attached < fps->workers_expected)
858-
ParallelWorkerNumber = fps->workers_attached++;
859-
SpinLockRelease(&fps->mutex);
860-
if (ParallelWorkerNumber < 0)
861-
ereport(ERROR,
862-
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
863-
errmsg("too many parallel workers already attached")));
864855
MyFixedParallelState = fps;
865856

866857
/*

src/backend/postmaster/bgworker.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,7 @@ BackgroundWorkerStateChange(void)
314314
rw->rw_worker.bgw_restart_time = slot->worker.bgw_restart_time;
315315
rw->rw_worker.bgw_main = slot->worker.bgw_main;
316316
rw->rw_worker.bgw_main_arg = slot->worker.bgw_main_arg;
317+
memcpy(rw->rw_worker.bgw_extra, slot->worker.bgw_extra, BGW_EXTRALEN);
317318

318319
/*
319320
* Copy the PID to be notified about state changes, but only if the

src/include/postmaster/bgworker.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ typedef enum
7474
#define BGW_DEFAULT_RESTART_INTERVAL 60
7575
#define BGW_NEVER_RESTART -1
7676
#define BGW_MAXLEN 64
77+
#define BGW_EXTRALEN 128
7778

7879
typedef struct BackgroundWorker
7980
{
@@ -85,6 +86,7 @@ typedef struct BackgroundWorker
8586
char bgw_library_name[BGW_MAXLEN]; /* only if bgw_main is NULL */
8687
char bgw_function_name[BGW_MAXLEN]; /* only if bgw_main is NULL */
8788
Datum bgw_main_arg;
89+
char bgw_extra[BGW_EXTRALEN];
8890
pid_t bgw_notify_pid; /* SIGUSR1 this backend on start/stop */
8991
} BackgroundWorker;
9092

0 commit comments

Comments
 (0)