Coverage Report

Created: 2026-11-12 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/access/transam/parallel.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * parallel.c
4
 *    Infrastructure for launching parallel workers
5
 *
6
 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7
 * Portions Copyright (c) 1994, Regents of the University of California
8
 *
9
 * IDENTIFICATION
10
 *    src/backend/access/transam/parallel.c
11
 *
12
 *-------------------------------------------------------------------------
13
 */
14
15
#include "postgres.h"
16
17
#include "access/brin.h"
18
#include "access/gin.h"
19
#include "access/nbtree.h"
20
#include "access/parallel.h"
21
#include "access/session.h"
22
#include "access/xact.h"
23
#include "access/xlog.h"
24
#include "catalog/index.h"
25
#include "catalog/namespace.h"
26
#include "catalog/pg_enum.h"
27
#include "catalog/storage.h"
28
#include "commands/async.h"
29
#include "commands/vacuum.h"
30
#include "executor/execParallel.h"
31
#include "libpq/libpq.h"
32
#include "libpq/pqformat.h"
33
#include "libpq/pqmq.h"
34
#include "miscadmin.h"
35
#include "optimizer/optimizer.h"
36
#include "pgstat.h"
37
#include "storage/ipc.h"
38
#include "storage/predicate.h"
39
#include "storage/proc.h"
40
#include "tcop/tcopprot.h"
41
#include "utils/combocid.h"
42
#include "utils/guc.h"
43
#include "utils/inval.h"
44
#include "utils/memutils.h"
45
#include "utils/relmapper.h"
46
#include "utils/snapmgr.h"
47
#include "utils/wait_event.h"
48
49
/*
50
 * We don't want to waste a lot of memory on an error queue which, most of
51
 * the time, will process only a handful of small messages.  However, it is
52
 * desirable to make it large enough that a typical ErrorResponse can be sent
53
 * without blocking.  That way, a worker that errors out can write the whole
54
 * message into the queue and terminate without waiting for the user backend.
55
 */
56
0
#define PARALLEL_ERROR_QUEUE_SIZE     16384
57
58
/* Magic number for parallel context TOC. */
59
0
#define PARALLEL_MAGIC            0x50477c7c
60
61
/*
62
 * Magic numbers for per-context parallel state sharing.  Higher-level code
63
 * should use smaller values, leaving these very large ones for use by this
64
 * module.
65
 */
66
0
#define PARALLEL_KEY_FIXED          UINT64CONST(0xFFFFFFFFFFFF0001)
67
0
#define PARALLEL_KEY_ERROR_QUEUE      UINT64CONST(0xFFFFFFFFFFFF0002)
68
0
#define PARALLEL_KEY_LIBRARY        UINT64CONST(0xFFFFFFFFFFFF0003)
69
0
#define PARALLEL_KEY_GUC          UINT64CONST(0xFFFFFFFFFFFF0004)
70
0
#define PARALLEL_KEY_COMBO_CID        UINT64CONST(0xFFFFFFFFFFFF0005)
71
0
#define PARALLEL_KEY_TRANSACTION_SNAPSHOT UINT64CONST(0xFFFFFFFFFFFF0006)
72
0
#define PARALLEL_KEY_ACTIVE_SNAPSHOT    UINT64CONST(0xFFFFFFFFFFFF0007)
73
0
#define PARALLEL_KEY_TRANSACTION_STATE    UINT64CONST(0xFFFFFFFFFFFF0008)
74
0
#define PARALLEL_KEY_ENTRYPOINT       UINT64CONST(0xFFFFFFFFFFFF0009)
75
0
#define PARALLEL_KEY_SESSION_DSM      UINT64CONST(0xFFFFFFFFFFFF000A)
76
0
#define PARALLEL_KEY_PENDING_SYNCS      UINT64CONST(0xFFFFFFFFFFFF000B)
77
0
#define PARALLEL_KEY_REINDEX_STATE      UINT64CONST(0xFFFFFFFFFFFF000C)
78
0
#define PARALLEL_KEY_RELMAPPER_STATE    UINT64CONST(0xFFFFFFFFFFFF000D)
79
0
#define PARALLEL_KEY_UNCOMMITTEDENUMS   UINT64CONST(0xFFFFFFFFFFFF000E)
80
0
#define PARALLEL_KEY_CLIENTCONNINFO     UINT64CONST(0xFFFFFFFFFFFF000F)
81
82
/* Fixed-size parallel state. */
83
typedef struct FixedParallelState
84
{
85
  /* Fixed-size state that workers must restore. */
86
  Oid     database_id;
87
  Oid     authenticated_user_id;
88
  Oid     session_user_id;
89
  Oid     outer_user_id;
90
  Oid     current_user_id;
91
  Oid     temp_namespace_id;
92
  Oid     temp_toast_namespace_id;
93
  int     sec_context;
94
  bool    session_user_is_superuser;
95
  bool    role_is_superuser;
96
  PGPROC     *parallel_leader_pgproc;
97
  pid_t   parallel_leader_pid;
98
  ProcNumber  parallel_leader_proc_number;
99
  TimestampTz xact_ts;
100
  TimestampTz stmt_ts;
101
  SerializableXactHandle serializable_xact_handle;
102
103
  /* Maximum XactLastRecEnd of any worker. */
104
  pg_atomic_uint64 last_xlog_end;
105
} FixedParallelState;
106
107
/*
108
 * Our parallel worker number.  We initialize this to -1, meaning that we are
109
 * not a parallel worker.  In parallel workers, it will be set to a value >= 0
110
 * and < the number of workers before any user code is invoked; each parallel
111
 * worker will get a different parallel worker number.
112
 */
113
int     ParallelWorkerNumber = -1;
114
115
/* Is there a parallel message pending which we need to receive? */
116
volatile sig_atomic_t ParallelMessagePending = false;
117
118
/* Are we initializing a parallel worker? */
119
bool    InitializingParallelWorker = false;
120
121
/* Pointer to our fixed parallel state. */
122
static FixedParallelState *MyFixedParallelState;
123
124
/* List of active parallel contexts. */
125
static dlist_head pcxt_list = DLIST_STATIC_INIT(pcxt_list);
126
127
/* Backend-local copy of data from FixedParallelState. */
128
static pid_t ParallelLeaderPid;
129
130
/*
131
 * List of internal parallel worker entry points.  We need this for
132
 * reasons explained in LookupParallelWorkerFunction(), below.
133
 */
134
static const struct
135
{
136
  const char *fn_name;
137
  parallel_worker_main_type fn_addr;
138
}     InternalParallelWorkers[] =
139
140
{
141
  {
142
    "ParallelQueryMain", ParallelQueryMain
143
  },
144
  {
145
    "_bt_parallel_build_main", _bt_parallel_build_main
146
  },
147
  {
148
    "_brin_parallel_build_main", _brin_parallel_build_main
149
  },
150
  {
151
    "_gin_parallel_build_main", _gin_parallel_build_main
152
  },
153
  {
154
    "parallel_vacuum_main", parallel_vacuum_main
155
  }
156
};
157
158
/* Private functions. */
159
static void ProcessParallelMessage(ParallelContext *pcxt, int i, StringInfo msg);
160
static void WaitForParallelWorkersToExit(ParallelContext *pcxt);
161
static parallel_worker_main_type LookupParallelWorkerFunction(const char *libraryname, const char *funcname);
162
static void ParallelWorkerShutdown(int code, Datum arg);
163
164
165
/*
166
 * Establish a new parallel context.  This should be done after entering
167
 * parallel mode, and (unless there is an error) the context should be
168
 * destroyed before exiting the current subtransaction.
169
 */
170
ParallelContext *
171
CreateParallelContext(const char *library_name, const char *function_name,
172
            int nworkers)
173
0
{
174
0
  MemoryContext oldcontext;
175
0
  ParallelContext *pcxt;
176
177
  /* It is unsafe to create a parallel context if not in parallel mode. */
178
0
  Assert(IsInParallelMode());
179
180
  /* Number of workers should be non-negative. */
181
0
  Assert(nworkers >= 0);
182
183
  /* We might be running in a short-lived memory context. */
184
0
  oldcontext = MemoryContextSwitchTo(TopTransactionContext);
185
186
  /* Initialize a new ParallelContext. */
187
0
  pcxt = palloc0_object(ParallelContext);
188
0
  pcxt->subid = GetCurrentSubTransactionId();
189
0
  pcxt->nworkers = nworkers;
190
0
  pcxt->nworkers_to_launch = nworkers;
191
0
  pcxt->library_name = pstrdup(library_name);
192
0
  pcxt->function_name = pstrdup(function_name);
193
0
  pcxt->error_context_stack = error_context_stack;
194
0
  shm_toc_initialize_estimator(&pcxt->estimator);
195
0
  dlist_push_head(&pcxt_list, &pcxt->node);
196
197
  /* Restore previous memory context. */
198
0
  MemoryContextSwitchTo(oldcontext);
199
200
0
  return pcxt;
201
0
}
202
203
/*
204
 * Establish the dynamic shared memory segment for a parallel context and
205
 * copy state and other bookkeeping information that will be needed by
206
 * parallel workers into it.
207
 */
208
void
209
InitializeParallelDSM(ParallelContext *pcxt)
210
0
{
211
0
  MemoryContext oldcontext;
212
0
  Size    library_len = 0;
213
0
  Size    guc_len = 0;
214
0
  Size    combocidlen = 0;
215
0
  Size    tsnaplen = 0;
216
0
  Size    asnaplen = 0;
217
0
  Size    tstatelen = 0;
218
0
  Size    pendingsyncslen = 0;
219
0
  Size    reindexlen = 0;
220
0
  Size    relmapperlen = 0;
221
0
  Size    uncommittedenumslen = 0;
222
0
  Size    clientconninfolen = 0;
223
0
  Size    segsize = 0;
224
0
  int     i;
225
0
  FixedParallelState *fps;
226
0
  dsm_handle  session_dsm_handle = DSM_HANDLE_INVALID;
227
0
  Snapshot  transaction_snapshot = GetTransactionSnapshot();
228
0
  Snapshot  active_snapshot = GetActiveSnapshot();
229
230
  /* We might be running in a very short-lived memory context. */
231
0
  oldcontext = MemoryContextSwitchTo(TopTransactionContext);
232
233
  /* Allow space to store the fixed-size parallel state. */
234
0
  shm_toc_estimate_chunk(&pcxt->estimator, sizeof(FixedParallelState));
235
0
  shm_toc_estimate_keys(&pcxt->estimator, 1);
236
237
  /*
238
   * If we manage to reach here while non-interruptible, it's unsafe to
239
   * launch any workers: we would fail to process interrupts sent by them.
240
   * We can deal with that edge case by pretending no workers were
241
   * requested.
242
   */
243
0
  if (!INTERRUPTS_CAN_BE_PROCESSED())
244
0
    pcxt->nworkers = 0;
245
246
  /*
247
   * Normally, the user will have requested at least one worker process, but
248
   * if by chance they have not, we can skip a bunch of things here.
249
   */
250
0
  if (pcxt->nworkers > 0)
251
0
  {
252
    /* Get (or create) the per-session DSM segment's handle. */
253
0
    session_dsm_handle = GetSessionDsmHandle();
254
255
    /*
256
     * If we weren't able to create a per-session DSM segment, then we can
257
     * continue but we can't safely launch any workers because their
258
     * record typmods would be incompatible so they couldn't exchange
259
     * tuples.
260
     */
261
0
    if (session_dsm_handle == DSM_HANDLE_INVALID)
262
0
      pcxt->nworkers = 0;
263
0
  }
264
265
0
  if (pcxt->nworkers > 0)
266
0
  {
267
0
    StaticAssertDecl(BUFFERALIGN(PARALLEL_ERROR_QUEUE_SIZE) ==
268
0
             PARALLEL_ERROR_QUEUE_SIZE,
269
0
             "parallel error queue size not buffer-aligned");
270
271
    /* Estimate space for various kinds of state sharing. */
272
0
    library_len = EstimateLibraryStateSpace();
273
0
    shm_toc_estimate_chunk(&pcxt->estimator, library_len);
274
0
    guc_len = EstimateGUCStateSpace();
275
0
    shm_toc_estimate_chunk(&pcxt->estimator, guc_len);
276
0
    combocidlen = EstimateComboCIDStateSpace();
277
0
    shm_toc_estimate_chunk(&pcxt->estimator, combocidlen);
278
0
    if (IsolationUsesXactSnapshot())
279
0
    {
280
0
      tsnaplen = EstimateSnapshotSpace(transaction_snapshot);
281
0
      shm_toc_estimate_chunk(&pcxt->estimator, tsnaplen);
282
0
    }
283
0
    asnaplen = EstimateSnapshotSpace(active_snapshot);
284
0
    shm_toc_estimate_chunk(&pcxt->estimator, asnaplen);
285
0
    tstatelen = EstimateTransactionStateSpace();
286
0
    shm_toc_estimate_chunk(&pcxt->estimator, tstatelen);
287
0
    shm_toc_estimate_chunk(&pcxt->estimator, sizeof(dsm_handle));
288
0
    pendingsyncslen = EstimatePendingSyncsSpace();
289
0
    shm_toc_estimate_chunk(&pcxt->estimator, pendingsyncslen);
290
0
    reindexlen = EstimateReindexStateSpace();
291
0
    shm_toc_estimate_chunk(&pcxt->estimator, reindexlen);
292
0
    relmapperlen = EstimateRelationMapSpace();
293
0
    shm_toc_estimate_chunk(&pcxt->estimator, relmapperlen);
294
0
    uncommittedenumslen = EstimateUncommittedEnumsSpace();
295
0
    shm_toc_estimate_chunk(&pcxt->estimator, uncommittedenumslen);
296
0
    clientconninfolen = EstimateClientConnectionInfoSpace();
297
0
    shm_toc_estimate_chunk(&pcxt->estimator, clientconninfolen);
298
    /* If you add more chunks here, you probably need to add keys. */
299
0
    shm_toc_estimate_keys(&pcxt->estimator, 12);
300
301
    /* Estimate space need for error queues. */
302
0
    shm_toc_estimate_chunk(&pcxt->estimator,
303
0
                 mul_size(PARALLEL_ERROR_QUEUE_SIZE,
304
0
                    pcxt->nworkers));
305
0
    shm_toc_estimate_keys(&pcxt->estimator, 1);
306
307
    /* Estimate how much we'll need for the entrypoint info. */
308
0
    shm_toc_estimate_chunk(&pcxt->estimator, strlen(pcxt->library_name) +
309
0
                 strlen(pcxt->function_name) + 2);
310
0
    shm_toc_estimate_keys(&pcxt->estimator, 1);
311
0
  }
312
313
  /*
314
   * Create DSM and initialize with new table of contents.  But if the user
315
   * didn't request any workers, then don't bother creating a dynamic shared
316
   * memory segment; instead, just use backend-private memory.
317
   *
318
   * Also, if we can't create a dynamic shared memory segment because the
319
   * maximum number of segments have already been created, then fall back to
320
   * backend-private memory, and plan not to use any workers.  We hope this
321
   * won't happen very often, but it's better to abandon the use of
322
   * parallelism than to fail outright.
323
   */
324
0
  segsize = shm_toc_estimate(&pcxt->estimator);
325
0
  if (pcxt->nworkers > 0)
326
0
    pcxt->seg = dsm_create(segsize, DSM_CREATE_NULL_IF_MAXSEGMENTS);
327
0
  if (pcxt->seg != NULL)
328
0
    pcxt->toc = shm_toc_create(PARALLEL_MAGIC,
329
0
                   dsm_segment_address(pcxt->seg),
330
0
                   segsize);
331
0
  else
332
0
  {
333
0
    pcxt->nworkers = 0;
334
0
    pcxt->private_memory = MemoryContextAlloc(TopMemoryContext, segsize);
335
0
    pcxt->toc = shm_toc_create(PARALLEL_MAGIC, pcxt->private_memory,
336
0
                   segsize);
337
0
  }
338
339
  /* Initialize fixed-size state in shared memory. */
340
0
  fps = (FixedParallelState *)
341
0
    shm_toc_allocate(pcxt->toc, sizeof(FixedParallelState));
342
0
  fps->database_id = MyDatabaseId;
343
0
  fps->authenticated_user_id = GetAuthenticatedUserId();
344
0
  fps->session_user_id = GetSessionUserId();
345
0
  fps->outer_user_id = GetCurrentRoleId();
346
0
  GetUserIdAndSecContext(&fps->current_user_id, &fps->sec_context);
347
0
  fps->session_user_is_superuser = GetSessionUserIsSuperuser();
348
0
  fps->role_is_superuser = current_role_is_superuser;
349
0
  GetTempNamespaceState(&fps->temp_namespace_id,
350
0
              &fps->temp_toast_namespace_id);
351
0
  fps->parallel_leader_pgproc = MyProc;
352
0
  fps->parallel_leader_pid = MyProcPid;
353
0
  fps->parallel_leader_proc_number = MyProcNumber;
354
0
  fps->xact_ts = GetCurrentTransactionStartTimestamp();
355
0
  fps->stmt_ts = GetCurrentStatementStartTimestamp();
356
0
  fps->serializable_xact_handle = ShareSerializableXact();
357
0
  pg_atomic_init_u64(&fps->last_xlog_end, InvalidXLogRecPtr);
358
0
  shm_toc_insert(pcxt->toc, PARALLEL_KEY_FIXED, fps);
359
360
  /* We can skip the rest of this if we're not budgeting for any workers. */
361
0
  if (pcxt->nworkers > 0)
362
0
  {
363
0
    char     *libraryspace;
364
0
    char     *gucspace;
365
0
    char     *combocidspace;
366
0
    char     *tsnapspace;
367
0
    char     *asnapspace;
368
0
    char     *tstatespace;
369
0
    char     *pendingsyncsspace;
370
0
    char     *reindexspace;
371
0
    char     *relmapperspace;
372
0
    char     *error_queue_space;
373
0
    char     *session_dsm_handle_space;
374
0
    char     *entrypointstate;
375
0
    char     *uncommittedenumsspace;
376
0
    char     *clientconninfospace;
377
0
    Size    lnamelen;
378
379
    /* Serialize shared libraries we have loaded. */
380
0
    libraryspace = shm_toc_allocate(pcxt->toc, library_len);
381
0
    SerializeLibraryState(library_len, libraryspace);
382
0
    shm_toc_insert(pcxt->toc, PARALLEL_KEY_LIBRARY, libraryspace);
383
384
    /* Serialize GUC settings. */
385
0
    gucspace = shm_toc_allocate(pcxt->toc, guc_len);
386
0
    SerializeGUCState(guc_len, gucspace);
387
0
    shm_toc_insert(pcxt->toc, PARALLEL_KEY_GUC, gucspace);
388
389
    /* Serialize combo CID state. */
390
0
    combocidspace = shm_toc_allocate(pcxt->toc, combocidlen);
391
0
    SerializeComboCIDState(combocidlen, combocidspace);
392
0
    shm_toc_insert(pcxt->toc, PARALLEL_KEY_COMBO_CID, combocidspace);
393
394
    /*
395
     * Serialize the transaction snapshot if the transaction isolation
396
     * level uses a transaction snapshot.
397
     */
398
0
    if (IsolationUsesXactSnapshot())
399
0
    {
400
0
      tsnapspace = shm_toc_allocate(pcxt->toc, tsnaplen);
401
0
      SerializeSnapshot(transaction_snapshot, tsnapspace);
402
0
      shm_toc_insert(pcxt->toc, PARALLEL_KEY_TRANSACTION_SNAPSHOT,
403
0
               tsnapspace);
404
0
    }
405
406
    /* Serialize the active snapshot. */
407
0
    asnapspace = shm_toc_allocate(pcxt->toc, asnaplen);
408
0
    SerializeSnapshot(active_snapshot, asnapspace);
409
0
    shm_toc_insert(pcxt->toc, PARALLEL_KEY_ACTIVE_SNAPSHOT, asnapspace);
410
411
    /* Provide the handle for per-session segment. */
412
0
    session_dsm_handle_space = shm_toc_allocate(pcxt->toc,
413
0
                          sizeof(dsm_handle));
414
0
    *(dsm_handle *) session_dsm_handle_space = session_dsm_handle;
415
0
    shm_toc_insert(pcxt->toc, PARALLEL_KEY_SESSION_DSM,
416
0
             session_dsm_handle_space);
417
418
    /* Serialize transaction state. */
419
0
    tstatespace = shm_toc_allocate(pcxt->toc, tstatelen);
420
0
    SerializeTransactionState(tstatelen, tstatespace);
421
0
    shm_toc_insert(pcxt->toc, PARALLEL_KEY_TRANSACTION_STATE, tstatespace);
422
423
    /* Serialize pending syncs. */
424
0
    pendingsyncsspace = shm_toc_allocate(pcxt->toc, pendingsyncslen);
425
0
    SerializePendingSyncs(pendingsyncslen, pendingsyncsspace);
426
0
    shm_toc_insert(pcxt->toc, PARALLEL_KEY_PENDING_SYNCS,
427
0
             pendingsyncsspace);
428
429
    /* Serialize reindex state. */
430
0
    reindexspace = shm_toc_allocate(pcxt->toc, reindexlen);
431
0
    SerializeReindexState(reindexlen, reindexspace);
432
0
    shm_toc_insert(pcxt->toc, PARALLEL_KEY_REINDEX_STATE, reindexspace);
433
434
    /* Serialize relmapper state. */
435
0
    relmapperspace = shm_toc_allocate(pcxt->toc, relmapperlen);
436
0
    SerializeRelationMap(relmapperlen, relmapperspace);
437
0
    shm_toc_insert(pcxt->toc, PARALLEL_KEY_RELMAPPER_STATE,
438
0
             relmapperspace);
439
440
    /* Serialize uncommitted enum state. */
441
0
    uncommittedenumsspace = shm_toc_allocate(pcxt->toc,
442
0
                         uncommittedenumslen);
443
0
    SerializeUncommittedEnums(uncommittedenumsspace, uncommittedenumslen);
444
0
    shm_toc_insert(pcxt->toc, PARALLEL_KEY_UNCOMMITTEDENUMS,
445
0
             uncommittedenumsspace);
446
447
    /* Serialize our ClientConnectionInfo. */
448
0
    clientconninfospace = shm_toc_allocate(pcxt->toc, clientconninfolen);
449
0
    SerializeClientConnectionInfo(clientconninfolen, clientconninfospace);
450
0
    shm_toc_insert(pcxt->toc, PARALLEL_KEY_CLIENTCONNINFO,
451
0
             clientconninfospace);
452
453
    /* Allocate space for worker information. */
454
0
    pcxt->worker = palloc0_array(ParallelWorkerInfo, pcxt->nworkers);
455
456
    /*
457
     * Establish error queues in dynamic shared memory.
458
     *
459
     * These queues should be used only for transmitting ErrorResponse,
460
     * NoticeResponse, and NotifyResponse protocol messages.  Tuple data
461
     * should be transmitted via separate (possibly larger?) queues.
462
     */
463
0
    error_queue_space =
464
0
      shm_toc_allocate(pcxt->toc,
465
0
               mul_size(PARALLEL_ERROR_QUEUE_SIZE,
466
0
                    pcxt->nworkers));
467
0
    for (i = 0; i < pcxt->nworkers; ++i)
468
0
    {
469
0
      char     *start;
470
0
      shm_mq     *mq;
471
472
0
      start = error_queue_space + i * PARALLEL_ERROR_QUEUE_SIZE;
473
0
      mq = shm_mq_create(start, PARALLEL_ERROR_QUEUE_SIZE);
474
0
      shm_mq_set_receiver(mq, MyProc);
475
0
      pcxt->worker[i].error_mqh = shm_mq_attach(mq, pcxt->seg, NULL);
476
0
    }
477
0
    shm_toc_insert(pcxt->toc, PARALLEL_KEY_ERROR_QUEUE, error_queue_space);
478
479
    /*
480
     * Serialize entrypoint information.  It's unsafe to pass function
481
     * pointers across processes, as the function pointer may be different
482
     * in each process in EXEC_BACKEND builds, so we always pass library
483
     * and function name.  (We use library name "postgres" for functions
484
     * in the core backend.)
485
     */
486
0
    lnamelen = strlen(pcxt->library_name);
487
0
    entrypointstate = shm_toc_allocate(pcxt->toc, lnamelen +
488
0
                       strlen(pcxt->function_name) + 2);
489
0
    strcpy(entrypointstate, pcxt->library_name);
490
0
    strcpy(entrypointstate + lnamelen + 1, pcxt->function_name);
491
0
    shm_toc_insert(pcxt->toc, PARALLEL_KEY_ENTRYPOINT, entrypointstate);
492
0
  }
493
494
  /* Update nworkers_to_launch, in case we changed nworkers above. */
495
0
  pcxt->nworkers_to_launch = pcxt->nworkers;
496
497
  /* Restore previous memory context. */
498
0
  MemoryContextSwitchTo(oldcontext);
499
0
}
500
501
/*
502
 * Reinitialize the dynamic shared memory segment for a parallel context such
503
 * that we could launch workers for it again.
504
 */
505
void
506
ReinitializeParallelDSM(ParallelContext *pcxt)
507
0
{
508
0
  MemoryContext oldcontext;
509
0
  FixedParallelState *fps;
510
511
  /* We might be running in a very short-lived memory context. */
512
0
  oldcontext = MemoryContextSwitchTo(TopTransactionContext);
513
514
  /* Wait for any old workers to exit. */
515
0
  if (pcxt->nworkers_launched > 0)
516
0
  {
517
0
    WaitForParallelWorkersToFinish(pcxt);
518
0
    WaitForParallelWorkersToExit(pcxt);
519
0
    pcxt->nworkers_launched = 0;
520
0
    if (pcxt->known_attached_workers)
521
0
    {
522
0
      pfree(pcxt->known_attached_workers);
523
0
      pcxt->known_attached_workers = NULL;
524
0
      pcxt->nknown_attached_workers = 0;
525
0
    }
526
0
  }
527
528
  /* Reset a few bits of fixed parallel state to a clean state. */
529
0
  fps = shm_toc_lookup(pcxt->toc, PARALLEL_KEY_FIXED, false);
530
0
  pg_atomic_write_u64(&fps->last_xlog_end, InvalidXLogRecPtr);
531
532
  /* Recreate error queues (if they exist). */
533
0
  if (pcxt->nworkers > 0)
534
0
  {
535
0
    char     *error_queue_space;
536
0
    int     i;
537
538
0
    error_queue_space =
539
0
      shm_toc_lookup(pcxt->toc, PARALLEL_KEY_ERROR_QUEUE, false);
540
0
    for (i = 0; i < pcxt->nworkers; ++i)
541
0
    {
542
0
      char     *start;
543
0
      shm_mq     *mq;
544
545
0
      start = error_queue_space + i * PARALLEL_ERROR_QUEUE_SIZE;
546
0
      mq = shm_mq_create(start, PARALLEL_ERROR_QUEUE_SIZE);
547
0
      shm_mq_set_receiver(mq, MyProc);
548
0
      pcxt->worker[i].error_mqh = shm_mq_attach(mq, pcxt->seg, NULL);
549
0
    }
550
0
  }
551
552
  /* Restore previous memory context. */
553
0
  MemoryContextSwitchTo(oldcontext);
554
0
}
555
556
/*
557
 * Reinitialize parallel workers for a parallel context such that we could
558
 * launch a different number of workers.  This is required for cases where
559
 * we need to reuse the same DSM segment, but the number of workers can
560
 * vary from run-to-run.
561
 */
562
void
563
ReinitializeParallelWorkers(ParallelContext *pcxt, int nworkers_to_launch)
564
0
{
565
  /*
566
   * The number of workers that need to be launched must be less than the
567
   * number of workers with which the parallel context is initialized.  But
568
   * the caller might not know that InitializeParallelDSM reduced nworkers,
569
   * so just silently trim the request.
570
   */
571
0
  pcxt->nworkers_to_launch = Min(pcxt->nworkers, nworkers_to_launch);
572
0
}
573
574
/*
575
 * Launch parallel workers.
576
 */
577
void
578
LaunchParallelWorkers(ParallelContext *pcxt)
579
0
{
580
0
  MemoryContext oldcontext;
581
0
  BackgroundWorker worker;
582
0
  int     i;
583
0
  bool    any_registrations_failed = false;
584
585
  /* Skip this if we have no workers. */
586
0
  if (pcxt->nworkers == 0 || pcxt->nworkers_to_launch == 0)
587
0
    return;
588
589
  /* We need to be a lock group leader. */
590
0
  BecomeLockGroupLeader();
591
592
  /* If we do have workers, we'd better have a DSM segment. */
593
0
  Assert(pcxt->seg != NULL);
594
595
  /* We might be running in a short-lived memory context. */
596
0
  oldcontext = MemoryContextSwitchTo(TopTransactionContext);
597
598
  /* Configure a worker. */
599
0
  memset(&worker, 0, sizeof(worker));
600
0
  snprintf(worker.bgw_name, BGW_MAXLEN, "parallel worker for PID %d",
601
0
       MyProcPid);
602
0
  snprintf(worker.bgw_type, BGW_MAXLEN, "parallel worker");
603
0
  worker.bgw_flags =
604
0
    BGWORKER_SHMEM_ACCESS | BGWORKER_BACKEND_DATABASE_CONNECTION
605
0
    | BGWORKER_CLASS_PARALLEL;
606
0
  worker.bgw_start_time = BgWorkerStart_ConsistentState;
607
0
  worker.bgw_restart_time = BGW_NEVER_RESTART;
608
0
  sprintf(worker.bgw_library_name, "postgres");
609
0
  sprintf(worker.bgw_function_name, "ParallelWorkerMain");
610
0
  worker.bgw_main_arg = UInt32GetDatum(dsm_segment_handle(pcxt->seg));
611
0
  worker.bgw_notify_pid = MyProcPid;
612
613
  /*
614
   * Start workers.
615
   *
616
   * The caller must be able to tolerate ending up with fewer workers than
617
   * expected, so there is no need to throw an error here if registration
618
   * fails.  It wouldn't help much anyway, because registering the worker in
619
   * no way guarantees that it will start up and initialize successfully.
620
   */
621
0
  for (i = 0; i < pcxt->nworkers_to_launch; ++i)
622
0
  {
623
0
    memcpy(worker.bgw_extra, &i, sizeof(int));
624
0
    if (!any_registrations_failed &&
625
0
      RegisterDynamicBackgroundWorker(&worker,
626
0
                      &pcxt->worker[i].bgwhandle))
627
0
    {
628
0
      shm_mq_set_handle(pcxt->worker[i].error_mqh,
629
0
                pcxt->worker[i].bgwhandle);
630
0
      pcxt->nworkers_launched++;
631
0
    }
632
0
    else
633
0
    {
634
      /*
635
       * If we weren't able to register the worker, then we've bumped up
636
       * against the max_worker_processes limit, and future
637
       * registrations will probably fail too, so arrange to skip them.
638
       * But we still have to execute this code for the remaining slots
639
       * to make sure that we forget about the error queues we budgeted
640
       * for those workers.  Otherwise, we'll wait for them to start,
641
       * but they never will.
642
       */
643
0
      any_registrations_failed = true;
644
0
      pcxt->worker[i].bgwhandle = NULL;
645
0
      shm_mq_detach(pcxt->worker[i].error_mqh);
646
0
      pcxt->worker[i].error_mqh = NULL;
647
0
    }
648
0
  }
649
650
  /*
651
   * Now that nworkers_launched has taken its final value, we can initialize
652
   * known_attached_workers.
653
   */
654
0
  if (pcxt->nworkers_launched > 0)
655
0
  {
656
0
    pcxt->known_attached_workers = palloc0_array(bool, pcxt->nworkers_launched);
657
0
    pcxt->nknown_attached_workers = 0;
658
0
  }
659
660
  /* Restore previous memory context. */
661
0
  MemoryContextSwitchTo(oldcontext);
662
0
}
663
664
/*
665
 * Wait for all workers to attach to their error queues, and throw an error if
666
 * any worker fails to do this.
667
 *
668
 * Callers can assume that if this function returns successfully, then the
669
 * number of workers given by pcxt->nworkers_launched have initialized and
670
 * attached to their error queues.  Whether or not these workers are guaranteed
671
 * to still be running depends on what code the caller asked them to run;
672
 * this function does not guarantee that they have not exited.  However, it
673
 * does guarantee that any workers which exited must have done so cleanly and
674
 * after successfully performing the work with which they were tasked.
675
 *
676
 * If this function is not called, then some of the workers that were launched
677
 * may not have been started due to a fork() failure, or may have exited during
678
 * early startup prior to attaching to the error queue, so nworkers_launched
679
 * cannot be viewed as completely reliable.  It will never be less than the
680
 * number of workers which actually started, but it might be more.  Any workers
681
 * that failed to start will still be discovered by
682
 * WaitForParallelWorkersToFinish and an error will be thrown at that time,
683
 * provided that function is eventually reached.
684
 *
685
 * In general, the leader process should do as much work as possible before
686
 * calling this function.  fork() failures and other early-startup failures
687
 * are very uncommon, and having the leader sit idle when it could be doing
688
 * useful work is undesirable.  However, if the leader needs to wait for
689
 * all of its workers or for a specific worker, it may want to call this
690
 * function before doing so.  If not, it must make some other provision for
691
 * the failure-to-start case, lest it wait forever.  On the other hand, a
692
 * leader which never waits for a worker that might not be started yet, or
693
 * at least never does so prior to WaitForParallelWorkersToFinish(), need not
694
 * call this function at all.
695
 */
696
void
697
WaitForParallelWorkersToAttach(ParallelContext *pcxt)
698
0
{
699
0
  int     i;
700
701
  /* Skip this if we have no launched workers. */
702
0
  if (pcxt->nworkers_launched == 0)
703
0
    return;
704
705
0
  for (;;)
706
0
  {
707
    /*
708
     * This will process any parallel messages that are pending and it may
709
     * also throw an error propagated from a worker.
710
     */
711
0
    CHECK_FOR_INTERRUPTS();
712
713
0
    for (i = 0; i < pcxt->nworkers_launched; ++i)
714
0
    {
715
0
      BgwHandleStatus status;
716
0
      shm_mq     *mq;
717
0
      int     rc;
718
0
      pid_t   pid;
719
720
0
      if (pcxt->known_attached_workers[i])
721
0
        continue;
722
723
      /*
724
       * If error_mqh is NULL, then the worker has already exited
725
       * cleanly.
726
       */
727
0
      if (pcxt->worker[i].error_mqh == NULL)
728
0
      {
729
0
        pcxt->known_attached_workers[i] = true;
730
0
        ++pcxt->nknown_attached_workers;
731
0
        continue;
732
0
      }
733
734
0
      status = GetBackgroundWorkerPid(pcxt->worker[i].bgwhandle, &pid);
735
0
      if (status == BGWH_STARTED)
736
0
      {
737
        /* Has the worker attached to the error queue? */
738
0
        mq = shm_mq_get_queue(pcxt->worker[i].error_mqh);
739
0
        if (shm_mq_get_sender(mq) != NULL)
740
0
        {
741
          /* Yes, so it is known to be attached. */
742
0
          pcxt->known_attached_workers[i] = true;
743
0
          ++pcxt->nknown_attached_workers;
744
0
        }
745
0
      }
746
0
      else if (status == BGWH_STOPPED)
747
0
      {
748
        /*
749
         * If the worker stopped without attaching to the error queue,
750
         * throw an error.
751
         */
752
0
        mq = shm_mq_get_queue(pcxt->worker[i].error_mqh);
753
0
        if (shm_mq_get_sender(mq) == NULL)
754
0
          ereport(ERROR,
755
0
              (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
756
0
               errmsg("parallel worker failed to initialize"),
757
0
               errhint("More details may be available in the server log.")));
758
759
0
        pcxt->known_attached_workers[i] = true;
760
0
        ++pcxt->nknown_attached_workers;
761
0
      }
762
0
      else
763
0
      {
764
        /*
765
         * Worker not yet started, so we must wait.  The postmaster
766
         * will notify us if the worker's state changes.  Our latch
767
         * might also get set for some other reason, but if so we'll
768
         * just end up waiting for the same worker again.
769
         */
770
0
        rc = WaitLatch(MyLatch,
771
0
                 WL_LATCH_SET | WL_EXIT_ON_PM_DEATH,
772
0
                 -1, WAIT_EVENT_BGWORKER_STARTUP);
773
774
0
        if (rc & WL_LATCH_SET)
775
0
          ResetLatch(MyLatch);
776
0
      }
777
0
    }
778
779
    /* If all workers are known to have started, we're done. */
780
0
    if (pcxt->nknown_attached_workers >= pcxt->nworkers_launched)
781
0
    {
782
0
      Assert(pcxt->nknown_attached_workers == pcxt->nworkers_launched);
783
0
      break;
784
0
    }
785
0
  }
786
0
}
787
788
/*
789
 * Wait for all workers to finish computing.
790
 *
791
 * Even if the parallel operation seems to have completed successfully, it's
792
 * important to call this function afterwards.  We must not miss any errors
793
 * the workers may have thrown during the parallel operation, or any that they
794
 * may yet throw while shutting down.
795
 *
796
 * Also, we want to update our notion of XactLastRecEnd based on worker
797
 * feedback.
798
 */
799
void
800
WaitForParallelWorkersToFinish(ParallelContext *pcxt)
801
0
{
802
0
  for (;;)
803
0
  {
804
0
    bool    anyone_alive = false;
805
0
    int     nfinished = 0;
806
0
    int     i;
807
808
    /*
809
     * This will process any parallel messages that are pending, which may
810
     * change the outcome of the loop that follows.  It may also throw an
811
     * error propagated from a worker.
812
     */
813
0
    CHECK_FOR_INTERRUPTS();
814
815
    /*
816
     * An autovacuum worker running a parallel vacuum (leader) propagates
817
     * changes to the cost-based delay parameters to its parallel workers
818
     * at its own cost delay points, which it no longer reaches while
819
     * waiting here. Do it here instead, on every wakeup, so that a config
820
     * reload or a change in the number of autovacuum workers sharing the
821
     * cost limit reaches the parallel workers before they finish.
822
     */
823
0
    if (AmAutoVacuumWorkerProcess())
824
0
      parallel_vacuum_refresh_cost_params();
825
826
0
    for (i = 0; i < pcxt->nworkers_launched; ++i)
827
0
    {
828
      /*
829
       * If error_mqh is NULL, then the worker has already exited
830
       * cleanly.  If we have received a message through error_mqh from
831
       * the worker, we know it started up cleanly, and therefore we're
832
       * certain to be notified when it exits.
833
       */
834
0
      if (pcxt->worker[i].error_mqh == NULL)
835
0
        ++nfinished;
836
0
      else if (pcxt->known_attached_workers[i])
837
0
      {
838
0
        anyone_alive = true;
839
0
        break;
840
0
      }
841
0
    }
842
843
0
    if (!anyone_alive)
844
0
    {
845
      /* If all workers are known to have finished, we're done. */
846
0
      if (nfinished >= pcxt->nworkers_launched)
847
0
      {
848
0
        Assert(nfinished == pcxt->nworkers_launched);
849
0
        break;
850
0
      }
851
852
      /*
853
       * We didn't detect any living workers, but not all workers are
854
       * known to have exited cleanly.  Either not all workers have
855
       * launched yet, or maybe some of them failed to start or
856
       * terminated abnormally.
857
       */
858
0
      for (i = 0; i < pcxt->nworkers_launched; ++i)
859
0
      {
860
0
        pid_t   pid;
861
0
        shm_mq     *mq;
862
863
        /*
864
         * If the worker is BGWH_NOT_YET_STARTED or BGWH_STARTED, we
865
         * should just keep waiting.  If it is BGWH_STOPPED, then
866
         * further investigation is needed.
867
         */
868
0
        if (pcxt->worker[i].error_mqh == NULL ||
869
0
          pcxt->worker[i].bgwhandle == NULL ||
870
0
          GetBackgroundWorkerPid(pcxt->worker[i].bgwhandle,
871
0
                       &pid) != BGWH_STOPPED)
872
0
          continue;
873
874
        /*
875
         * Check whether the worker ended up stopped without ever
876
         * attaching to the error queue.  If so, the postmaster was
877
         * unable to fork the worker or it exited without initializing
878
         * properly.  We must throw an error, since the caller may
879
         * have been expecting the worker to do some work before
880
         * exiting.
881
         */
882
0
        mq = shm_mq_get_queue(pcxt->worker[i].error_mqh);
883
0
        if (shm_mq_get_sender(mq) == NULL)
884
0
          ereport(ERROR,
885
0
              (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
886
0
               errmsg("parallel worker failed to initialize"),
887
0
               errhint("More details may be available in the server log.")));
888
889
        /*
890
         * The worker is stopped, but is attached to the error queue.
891
         * Unless there's a bug somewhere, this will only happen when
892
         * the worker writes messages and terminates after the
893
         * CHECK_FOR_INTERRUPTS() near the top of this function and
894
         * before the call to GetBackgroundWorkerPid().  In that case,
895
         * our latch should have been set as well and the right things
896
         * will happen on the next pass through the loop.
897
         */
898
0
      }
899
0
    }
900
901
0
    (void) WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, -1,
902
0
             WAIT_EVENT_PARALLEL_FINISH);
903
0
    ResetLatch(MyLatch);
904
0
  }
905
906
0
  if (pcxt->toc != NULL)
907
0
  {
908
0
    FixedParallelState *fps;
909
0
    XLogRecPtr  last_xlog_end;
910
911
0
    fps = shm_toc_lookup(pcxt->toc, PARALLEL_KEY_FIXED, false);
912
0
    last_xlog_end = pg_atomic_read_u64(&fps->last_xlog_end);
913
0
    if (last_xlog_end > XactLastRecEnd)
914
0
      XactLastRecEnd = last_xlog_end;
915
0
  }
916
0
}
917
918
/*
919
 * Wait for all workers to exit.
920
 *
921
 * This function ensures that workers have been completely shutdown.  The
922
 * difference between WaitForParallelWorkersToFinish and this function is
923
 * that the former just ensures that last message sent by a worker backend is
924
 * received by the leader backend whereas this ensures the complete shutdown.
925
 */
926
static void
927
WaitForParallelWorkersToExit(ParallelContext *pcxt)
928
0
{
929
0
  int     i;
930
931
  /* Wait until the workers actually die. */
932
0
  for (i = 0; i < pcxt->nworkers_launched; ++i)
933
0
  {
934
0
    BgwHandleStatus status;
935
936
0
    if (pcxt->worker == NULL || pcxt->worker[i].bgwhandle == NULL)
937
0
      continue;
938
939
0
    status = WaitForBackgroundWorkerShutdown(pcxt->worker[i].bgwhandle);
940
941
    /*
942
     * If the postmaster kicked the bucket, we have no chance of cleaning
943
     * up safely -- we won't be able to tell when our workers are actually
944
     * dead.  This doesn't necessitate a PANIC since they will all abort
945
     * eventually, but we can't safely continue this session.
946
     */
947
0
    if (status == BGWH_POSTMASTER_DIED)
948
0
      ereport(FATAL,
949
0
          (errcode(ERRCODE_ADMIN_SHUTDOWN),
950
0
           errmsg("postmaster exited during a parallel transaction")));
951
952
    /* Release memory. */
953
0
    pfree(pcxt->worker[i].bgwhandle);
954
0
    pcxt->worker[i].bgwhandle = NULL;
955
0
  }
956
0
}
957
958
/*
959
 * Destroy a parallel context.
960
 *
961
 * If expecting a clean exit, you should use WaitForParallelWorkersToFinish()
962
 * first, before calling this function.  When this function is invoked, any
963
 * remaining workers are forcibly killed; the dynamic shared memory segment
964
 * is unmapped; and we then wait (uninterruptibly) for the workers to exit.
965
 */
966
void
967
DestroyParallelContext(ParallelContext *pcxt)
968
0
{
969
0
  int     i;
970
971
  /*
972
   * Be careful about order of operations here!  We remove the parallel
973
   * context from the list before we do anything else; otherwise, if an
974
   * error occurs during a subsequent step, we might try to nuke it again
975
   * from AtEOXact_Parallel or AtEOSubXact_Parallel.
976
   */
977
0
  dlist_delete(&pcxt->node);
978
979
  /* Kill each worker in turn, and forget their error queues. */
980
0
  if (pcxt->worker != NULL)
981
0
  {
982
0
    for (i = 0; i < pcxt->nworkers_launched; ++i)
983
0
    {
984
0
      if (pcxt->worker[i].error_mqh != NULL)
985
0
      {
986
0
        TerminateBackgroundWorker(pcxt->worker[i].bgwhandle);
987
988
0
        shm_mq_detach(pcxt->worker[i].error_mqh);
989
0
        pcxt->worker[i].error_mqh = NULL;
990
0
      }
991
0
    }
992
0
  }
993
994
  /*
995
   * If we have allocated a shared memory segment, detach it.  This will
996
   * implicitly detach the error queues, and any other shared memory queues,
997
   * stored there.
998
   */
999
0
  if (pcxt->seg != NULL)
1000
0
  {
1001
0
    dsm_detach(pcxt->seg);
1002
0
    pcxt->seg = NULL;
1003
0
  }
1004
1005
  /*
1006
   * If this parallel context is actually in backend-private memory rather
1007
   * than shared memory, free that memory instead.
1008
   */
1009
0
  if (pcxt->private_memory != NULL)
1010
0
  {
1011
0
    pfree(pcxt->private_memory);
1012
0
    pcxt->private_memory = NULL;
1013
0
  }
1014
1015
  /*
1016
   * We can't finish transaction commit or abort until all of the workers
1017
   * have exited.  This means, in particular, that we can't respond to
1018
   * interrupts at this stage.
1019
   */
1020
0
  HOLD_INTERRUPTS();
1021
0
  WaitForParallelWorkersToExit(pcxt);
1022
0
  RESUME_INTERRUPTS();
1023
1024
  /* Free the worker array itself. */
1025
0
  if (pcxt->worker != NULL)
1026
0
  {
1027
0
    pfree(pcxt->worker);
1028
0
    pcxt->worker = NULL;
1029
0
  }
1030
1031
  /* Free memory. */
1032
0
  pfree(pcxt->library_name);
1033
0
  pfree(pcxt->function_name);
1034
0
  pfree(pcxt);
1035
0
}
1036
1037
/*
1038
 * Are there any parallel contexts currently active?
1039
 */
1040
bool
1041
ParallelContextActive(void)
1042
0
{
1043
0
  return !dlist_is_empty(&pcxt_list);
1044
0
}
1045
1046
/*
1047
 * Handle receipt of an interrupt indicating a parallel worker message.
1048
 *
1049
 * Note: this is called within a signal handler!  All we can do is set
1050
 * a flag that will cause the next CHECK_FOR_INTERRUPTS() to invoke
1051
 * ProcessParallelMessages().
1052
 */
1053
void
1054
HandleParallelMessageInterrupt(void)
1055
0
{
1056
0
  InterruptPending = true;
1057
0
  ParallelMessagePending = true;
1058
  /* latch will be set by procsignal_sigusr1_handler */
1059
0
}
1060
1061
/*
1062
 * Process any queued protocol messages received from parallel workers.
1063
 */
1064
void
1065
ProcessParallelMessages(void)
1066
0
{
1067
0
  dlist_iter  iter;
1068
0
  MemoryContext oldcontext;
1069
1070
0
  static MemoryContext hpm_context = NULL;
1071
1072
  /*
1073
   * This is invoked from ProcessInterrupts(), and since some of the
1074
   * functions it calls contain CHECK_FOR_INTERRUPTS(), there is a potential
1075
   * for recursive calls if more signals are received while this runs.  It's
1076
   * unclear that recursive entry would be safe, and it doesn't seem useful
1077
   * even if it is safe, so let's block interrupts until done.
1078
   */
1079
0
  HOLD_INTERRUPTS();
1080
1081
  /*
1082
   * Moreover, CurrentMemoryContext might be pointing almost anywhere.  We
1083
   * don't want to risk leaking data into long-lived contexts, so let's do
1084
   * our work here in a private context that we can reset on each use.
1085
   */
1086
0
  if (hpm_context == NULL) /* first time through? */
1087
0
    hpm_context = AllocSetContextCreate(TopMemoryContext,
1088
0
                      "ProcessParallelMessages",
1089
0
                      ALLOCSET_DEFAULT_SIZES);
1090
0
  else
1091
0
    MemoryContextReset(hpm_context);
1092
1093
0
  oldcontext = MemoryContextSwitchTo(hpm_context);
1094
1095
  /* OK to process messages.  Reset the flag saying there are more to do. */
1096
0
  ParallelMessagePending = false;
1097
1098
0
  dlist_foreach(iter, &pcxt_list)
1099
0
  {
1100
0
    ParallelContext *pcxt;
1101
0
    int     i;
1102
1103
0
    pcxt = dlist_container(ParallelContext, node, iter.cur);
1104
0
    if (pcxt->worker == NULL)
1105
0
      continue;
1106
1107
0
    for (i = 0; i < pcxt->nworkers_launched; ++i)
1108
0
    {
1109
      /*
1110
       * Read as many messages as we can from each worker, but stop when
1111
       * either (1) the worker's error queue goes away, which can happen
1112
       * if we receive a Terminate message from the worker; or (2) no
1113
       * more messages can be read from the worker without blocking.
1114
       */
1115
0
      while (pcxt->worker[i].error_mqh != NULL)
1116
0
      {
1117
0
        shm_mq_result res;
1118
0
        Size    nbytes;
1119
0
        void     *data;
1120
1121
0
        res = shm_mq_receive(pcxt->worker[i].error_mqh, &nbytes,
1122
0
                   &data, true);
1123
0
        if (res == SHM_MQ_WOULD_BLOCK)
1124
0
          break;
1125
0
        else if (res == SHM_MQ_SUCCESS)
1126
0
        {
1127
0
          StringInfoData msg;
1128
1129
0
          initStringInfo(&msg);
1130
0
          appendBinaryStringInfo(&msg, data, nbytes);
1131
0
          ProcessParallelMessage(pcxt, i, &msg);
1132
0
          pfree(msg.data);
1133
0
        }
1134
0
        else
1135
0
          ereport(ERROR,
1136
0
              (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1137
0
               errmsg("lost connection to parallel worker")));
1138
0
      }
1139
0
    }
1140
0
  }
1141
1142
0
  MemoryContextSwitchTo(oldcontext);
1143
1144
  /* Might as well clear the context on our way out */
1145
0
  MemoryContextReset(hpm_context);
1146
1147
0
  RESUME_INTERRUPTS();
1148
0
}
1149
1150
/*
1151
 * Process a single protocol message received from a single parallel worker.
1152
 */
1153
static void
1154
ProcessParallelMessage(ParallelContext *pcxt, int i, StringInfo msg)
1155
0
{
1156
0
  char    msgtype;
1157
1158
0
  if (pcxt->known_attached_workers != NULL &&
1159
0
    !pcxt->known_attached_workers[i])
1160
0
  {
1161
0
    pcxt->known_attached_workers[i] = true;
1162
0
    pcxt->nknown_attached_workers++;
1163
0
  }
1164
1165
0
  msgtype = pq_getmsgbyte(msg);
1166
1167
0
  switch (msgtype)
1168
0
  {
1169
0
    case PqMsg_ErrorResponse:
1170
0
    case PqMsg_NoticeResponse:
1171
0
      {
1172
0
        ErrorData edata;
1173
0
        ErrorContextCallback *save_error_context_stack;
1174
1175
        /* Parse ErrorResponse or NoticeResponse. */
1176
0
        pq_parse_errornotice(msg, &edata);
1177
1178
        /* Death of a worker isn't enough justification for suicide. */
1179
0
        edata.elevel = Min(edata.elevel, ERROR);
1180
1181
        /*
1182
         * If desired, add a context line to show that this is a
1183
         * message propagated from a parallel worker.  Otherwise, it
1184
         * can sometimes be confusing to understand what actually
1185
         * happened.  (We don't do this in DEBUG_PARALLEL_REGRESS mode
1186
         * because it causes test-result instability depending on
1187
         * whether a parallel worker is actually used or not.)
1188
         */
1189
0
        if (debug_parallel_query != DEBUG_PARALLEL_REGRESS)
1190
0
        {
1191
0
          if (edata.context)
1192
0
            edata.context = psprintf("%s\n%s", edata.context,
1193
0
                         _("parallel worker"));
1194
0
          else
1195
0
            edata.context = pstrdup(_("parallel worker"));
1196
0
        }
1197
1198
        /*
1199
         * Context beyond that should use the error context callbacks
1200
         * that were in effect when the ParallelContext was created,
1201
         * not the current ones.
1202
         */
1203
0
        save_error_context_stack = error_context_stack;
1204
0
        error_context_stack = pcxt->error_context_stack;
1205
1206
        /* Rethrow error or print notice. */
1207
0
        ThrowErrorData(&edata);
1208
1209
        /* Not an error, so restore previous context stack. */
1210
0
        error_context_stack = save_error_context_stack;
1211
1212
0
        break;
1213
0
      }
1214
1215
0
    case PqMsg_NotificationResponse:
1216
0
      {
1217
        /* Propagate NotifyResponse. */
1218
0
        int32   pid;
1219
0
        const char *channel;
1220
0
        const char *payload;
1221
1222
0
        pid = pq_getmsgint(msg, 4);
1223
0
        channel = pq_getmsgrawstring(msg);
1224
0
        payload = pq_getmsgrawstring(msg);
1225
0
        pq_endmessage(msg);
1226
1227
0
        NotifyMyFrontEnd(channel, payload, pid);
1228
1229
0
        break;
1230
0
      }
1231
1232
0
    case PqParallelMsg_Progress:
1233
0
      {
1234
        /*
1235
         * Only incremental progress reporting is currently supported.
1236
         * However, it's possible to add more fields to the message to
1237
         * allow for handling of other backend progress APIs.
1238
         */
1239
0
        int     index = pq_getmsgint(msg, 4);
1240
0
        int64   incr = pq_getmsgint64(msg);
1241
1242
0
        pq_getmsgend(msg);
1243
1244
0
        pgstat_progress_incr_param(index, incr);
1245
1246
0
        break;
1247
0
      }
1248
1249
0
    case PqMsg_Terminate:
1250
0
      {
1251
0
        shm_mq_detach(pcxt->worker[i].error_mqh);
1252
0
        pcxt->worker[i].error_mqh = NULL;
1253
0
        break;
1254
0
      }
1255
1256
0
    default:
1257
0
      {
1258
0
        elog(ERROR, "unrecognized message type received from parallel worker: %c (message length %d bytes)",
1259
0
           msgtype, msg->len);
1260
0
      }
1261
0
  }
1262
0
}
1263
1264
/*
1265
 * End-of-subtransaction cleanup for parallel contexts.
1266
 *
1267
 * Here we remove only parallel contexts initiated within the current
1268
 * subtransaction.
1269
 */
1270
void
1271
AtEOSubXact_Parallel(bool isCommit, SubTransactionId mySubId)
1272
{
1273
  while (!dlist_is_empty(&pcxt_list))
1274
  {
1275
    ParallelContext *pcxt;
1276
1277
    pcxt = dlist_head_element(ParallelContext, node, &pcxt_list);
1278
    if (pcxt->subid != mySubId)
1279
      break;
1280
    if (isCommit)
1281
      elog(WARNING, "leaked parallel context");
1282
    DestroyParallelContext(pcxt);
1283
  }
1284
}
1285
1286
/*
1287
 * End-of-transaction cleanup for parallel contexts.
1288
 *
1289
 * We nuke all remaining parallel contexts.
1290
 */
1291
void
1292
AtEOXact_Parallel(bool isCommit)
1293
{
1294
  while (!dlist_is_empty(&pcxt_list))
1295
  {
1296
    ParallelContext *pcxt;
1297
1298
    pcxt = dlist_head_element(ParallelContext, node, &pcxt_list);
1299
    if (isCommit)
1300
      elog(WARNING, "leaked parallel context");
1301
    DestroyParallelContext(pcxt);
1302
  }
1303
}
1304
1305
/*
1306
 * Main entrypoint for parallel workers.
1307
 */
1308
void
1309
ParallelWorkerMain(Datum main_arg)
1310
0
{
1311
0
  dsm_segment *seg;
1312
0
  shm_toc    *toc;
1313
0
  FixedParallelState *fps;
1314
0
  char     *error_queue_space;
1315
0
  shm_mq     *mq;
1316
0
  shm_mq_handle *mqh;
1317
0
  char     *libraryspace;
1318
0
  char     *entrypointstate;
1319
0
  char     *library_name;
1320
0
  char     *function_name;
1321
0
  parallel_worker_main_type entrypt;
1322
0
  char     *gucspace;
1323
0
  char     *combocidspace;
1324
0
  char     *tsnapspace;
1325
0
  char     *asnapspace;
1326
0
  char     *tstatespace;
1327
0
  char     *pendingsyncsspace;
1328
0
  char     *reindexspace;
1329
0
  char     *relmapperspace;
1330
0
  char     *uncommittedenumsspace;
1331
0
  char     *clientconninfospace;
1332
0
  char     *session_dsm_handle_space;
1333
0
  Snapshot  tsnapshot;
1334
0
  Snapshot  asnapshot;
1335
1336
  /* Set flag to indicate that we're initializing a parallel worker. */
1337
0
  InitializingParallelWorker = true;
1338
1339
  /* Establish signal handlers. */
1340
0
  BackgroundWorkerUnblockSignals();
1341
1342
  /* Determine and set our parallel worker number. */
1343
0
  Assert(ParallelWorkerNumber == -1);
1344
0
  memcpy(&ParallelWorkerNumber, MyBgworkerEntry->bgw_extra, sizeof(int));
1345
1346
  /* Set up a memory context to work in, just for cleanliness. */
1347
0
  CurrentMemoryContext = AllocSetContextCreate(TopMemoryContext,
1348
0
                         "Parallel worker",
1349
0
                         ALLOCSET_DEFAULT_SIZES);
1350
1351
  /*
1352
   * Attach to the dynamic shared memory segment for the parallel query, and
1353
   * find its table of contents.
1354
   *
1355
   * Note: at this point, we have not created any ResourceOwner in this
1356
   * process.  This will result in our DSM mapping surviving until process
1357
   * exit, which is fine.  If there were a ResourceOwner, it would acquire
1358
   * ownership of the mapping, but we have no need for that.
1359
   */
1360
0
  seg = dsm_attach(DatumGetUInt32(main_arg));
1361
0
  if (seg == NULL)
1362
0
    ereport(ERROR,
1363
0
        (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1364
0
         errmsg("could not map dynamic shared memory segment")));
1365
0
  toc = shm_toc_attach(PARALLEL_MAGIC, dsm_segment_address(seg));
1366
0
  if (toc == NULL)
1367
0
    ereport(ERROR,
1368
0
        (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1369
0
         errmsg("invalid magic number in dynamic shared memory segment")));
1370
1371
  /* Look up fixed parallel state. */
1372
0
  fps = shm_toc_lookup(toc, PARALLEL_KEY_FIXED, false);
1373
0
  MyFixedParallelState = fps;
1374
1375
  /* Arrange to signal the leader if we exit. */
1376
0
  ParallelLeaderPid = fps->parallel_leader_pid;
1377
0
  ParallelLeaderProcNumber = fps->parallel_leader_proc_number;
1378
0
  before_shmem_exit(ParallelWorkerShutdown, PointerGetDatum(seg));
1379
1380
  /*
1381
   * Now we can find and attach to the error queue provided for us.  That's
1382
   * good, because until we do that, any errors that happen here will not be
1383
   * reported back to the process that requested that this worker be
1384
   * launched.
1385
   */
1386
0
  error_queue_space = shm_toc_lookup(toc, PARALLEL_KEY_ERROR_QUEUE, false);
1387
0
  mq = (shm_mq *) (error_queue_space +
1388
0
           ParallelWorkerNumber * PARALLEL_ERROR_QUEUE_SIZE);
1389
0
  shm_mq_set_sender(mq, MyProc);
1390
0
  mqh = shm_mq_attach(mq, seg, NULL);
1391
0
  pq_redirect_to_shm_mq(seg, mqh);
1392
0
  pq_set_parallel_leader(fps->parallel_leader_pid,
1393
0
               fps->parallel_leader_proc_number);
1394
1395
  /*
1396
   * Hooray! Primary initialization is complete.  Now, we need to set up our
1397
   * backend-local state to match the original backend.
1398
   */
1399
1400
  /*
1401
   * Join locking group.  We must do this before anything that could try to
1402
   * acquire a heavyweight lock, because any heavyweight locks acquired to
1403
   * this point could block either directly against the parallel group
1404
   * leader or against some process which in turn waits for a lock that
1405
   * conflicts with the parallel group leader, causing an undetected
1406
   * deadlock.  (If we can't join the lock group, the leader has gone away,
1407
   * so just exit quietly.)
1408
   */
1409
0
  if (!BecomeLockGroupMember(fps->parallel_leader_pgproc,
1410
0
                 fps->parallel_leader_pid))
1411
0
    return;
1412
1413
  /*
1414
   * Restore transaction and statement start-time timestamps.  This must
1415
   * happen before anything that would start a transaction, else asserts in
1416
   * xact.c will fire.
1417
   */
1418
0
  SetParallelStartTimestamps(fps->xact_ts, fps->stmt_ts);
1419
1420
  /*
1421
   * Identify the entry point to be called.  In theory this could result in
1422
   * loading an additional library, though most likely the entry point is in
1423
   * the core backend or in a library we just loaded.
1424
   */
1425
0
  entrypointstate = shm_toc_lookup(toc, PARALLEL_KEY_ENTRYPOINT, false);
1426
0
  library_name = entrypointstate;
1427
0
  function_name = entrypointstate + strlen(library_name) + 1;
1428
1429
0
  entrypt = LookupParallelWorkerFunction(library_name, function_name);
1430
1431
  /*
1432
   * Restore current session authorization and role id.  No verification
1433
   * happens here, we just blindly adopt the leader's state.  Note that this
1434
   * has to happen before InitPostgres, since InitializeSessionUserId will
1435
   * not set these variables.
1436
   */
1437
0
  SetAuthenticatedUserId(fps->authenticated_user_id);
1438
0
  SetSessionAuthorization(fps->session_user_id,
1439
0
              fps->session_user_is_superuser);
1440
0
  SetCurrentRoleId(fps->outer_user_id, fps->role_is_superuser);
1441
1442
  /*
1443
   * Restore database connection.  We skip connection authorization checks,
1444
   * reasoning that (a) the leader checked these things when it started, and
1445
   * (b) we do not want parallel mode to cause these failures, because that
1446
   * would make use of parallel query plans not transparent to applications.
1447
   */
1448
0
  BackgroundWorkerInitializeConnectionByOid(fps->database_id,
1449
0
                        fps->authenticated_user_id,
1450
0
                        BGWORKER_BYPASS_ALLOWCONN |
1451
0
                        BGWORKER_BYPASS_ROLELOGINCHECK);
1452
1453
  /*
1454
   * Set the client encoding to the database encoding, since that is what
1455
   * the leader will expect.  (We're cheating a bit by not calling
1456
   * PrepareClientEncoding first.  It's okay because this call will always
1457
   * result in installing a no-op conversion.  No error should be possible,
1458
   * but check anyway.)
1459
   */
1460
0
  if (SetClientEncoding(GetDatabaseEncoding()) < 0)
1461
0
    elog(ERROR, "SetClientEncoding(%d) failed", GetDatabaseEncoding());
1462
1463
  /*
1464
   * Load libraries that were loaded by original backend.  We want to do
1465
   * this before restoring GUCs, because the libraries might define custom
1466
   * variables.
1467
   */
1468
0
  libraryspace = shm_toc_lookup(toc, PARALLEL_KEY_LIBRARY, false);
1469
0
  StartTransactionCommand();
1470
0
  RestoreLibraryState(libraryspace);
1471
0
  CommitTransactionCommand();
1472
1473
  /* Crank up a transaction state appropriate to a parallel worker. */
1474
0
  tstatespace = shm_toc_lookup(toc, PARALLEL_KEY_TRANSACTION_STATE, false);
1475
0
  StartParallelWorkerTransaction(tstatespace);
1476
1477
  /*
1478
   * Restore state that affects catalog access.  Ideally we'd do this even
1479
   * before calling InitPostgres, but that has order-of-initialization
1480
   * problems, and also the relmapper would get confused during the
1481
   * CommitTransactionCommand call above.
1482
   */
1483
0
  pendingsyncsspace = shm_toc_lookup(toc, PARALLEL_KEY_PENDING_SYNCS,
1484
0
                     false);
1485
0
  RestorePendingSyncs(pendingsyncsspace);
1486
0
  relmapperspace = shm_toc_lookup(toc, PARALLEL_KEY_RELMAPPER_STATE, false);
1487
0
  RestoreRelationMap(relmapperspace);
1488
0
  reindexspace = shm_toc_lookup(toc, PARALLEL_KEY_REINDEX_STATE, false);
1489
0
  RestoreReindexState(reindexspace);
1490
0
  combocidspace = shm_toc_lookup(toc, PARALLEL_KEY_COMBO_CID, false);
1491
0
  RestoreComboCIDState(combocidspace);
1492
1493
  /* Attach to the per-session DSM segment and contained objects. */
1494
0
  session_dsm_handle_space =
1495
0
    shm_toc_lookup(toc, PARALLEL_KEY_SESSION_DSM, false);
1496
0
  AttachSession(*(dsm_handle *) session_dsm_handle_space);
1497
1498
  /*
1499
   * If the transaction isolation level is REPEATABLE READ or SERIALIZABLE,
1500
   * the leader has serialized the transaction snapshot and we must restore
1501
   * it. At lower isolation levels, there is no transaction-lifetime
1502
   * snapshot, but we need TransactionXmin to get set to a value which is
1503
   * less than or equal to the xmin of every snapshot that will be used by
1504
   * this worker. The easiest way to accomplish that is to install the
1505
   * active snapshot as the transaction snapshot. Code running in this
1506
   * parallel worker might take new snapshots via GetTransactionSnapshot()
1507
   * or GetLatestSnapshot(), but it shouldn't have any way of acquiring a
1508
   * snapshot older than the active snapshot.
1509
   */
1510
0
  asnapspace = shm_toc_lookup(toc, PARALLEL_KEY_ACTIVE_SNAPSHOT, false);
1511
0
  tsnapspace = shm_toc_lookup(toc, PARALLEL_KEY_TRANSACTION_SNAPSHOT, true);
1512
0
  asnapshot = RestoreSnapshot(asnapspace);
1513
0
  tsnapshot = tsnapspace ? RestoreSnapshot(tsnapspace) : asnapshot;
1514
0
  RestoreTransactionSnapshot(tsnapshot,
1515
0
                 fps->parallel_leader_pgproc);
1516
0
  PushActiveSnapshot(asnapshot);
1517
1518
  /*
1519
   * We've changed which tuples we can see, and must therefore invalidate
1520
   * system caches.
1521
   */
1522
0
  InvalidateSystemCaches();
1523
1524
  /*
1525
   * Restore GUC values from launching backend.  We can't do this earlier,
1526
   * because GUC check hooks that do catalog lookups need to see the same
1527
   * database state as the leader.  Also, the check hooks for
1528
   * session_authorization and role assume we already set the correct role
1529
   * OIDs.
1530
   */
1531
0
  gucspace = shm_toc_lookup(toc, PARALLEL_KEY_GUC, false);
1532
0
  RestoreGUCState(gucspace);
1533
1534
  /*
1535
   * Restore current user ID and security context.  No verification happens
1536
   * here, we just blindly adopt the leader's state.  We can't do this till
1537
   * after restoring GUCs, else we'll get complaints about restoring
1538
   * session_authorization and role.  (In effect, we're assuming that all
1539
   * the restored values are okay to set, even if we are now inside a
1540
   * restricted context.)
1541
   */
1542
0
  SetUserIdAndSecContext(fps->current_user_id, fps->sec_context);
1543
1544
  /* Restore temp-namespace state to ensure search path matches leader's. */
1545
0
  SetTempNamespaceState(fps->temp_namespace_id,
1546
0
              fps->temp_toast_namespace_id);
1547
1548
  /* Restore uncommitted enums. */
1549
0
  uncommittedenumsspace = shm_toc_lookup(toc, PARALLEL_KEY_UNCOMMITTEDENUMS,
1550
0
                       false);
1551
0
  RestoreUncommittedEnums(uncommittedenumsspace);
1552
1553
  /* Restore the ClientConnectionInfo. */
1554
0
  clientconninfospace = shm_toc_lookup(toc, PARALLEL_KEY_CLIENTCONNINFO,
1555
0
                     false);
1556
0
  RestoreClientConnectionInfo(clientconninfospace);
1557
1558
  /*
1559
   * Initialize SystemUser now that MyClientConnectionInfo is restored. Also
1560
   * ensure that auth_method is actually valid, aka authn_id is not NULL.
1561
   */
1562
0
  if (MyClientConnectionInfo.authn_id)
1563
0
    InitializeSystemUser(MyClientConnectionInfo.authn_id,
1564
0
               hba_authname(MyClientConnectionInfo.auth_method));
1565
1566
  /* Attach to the leader's serializable transaction, if SERIALIZABLE. */
1567
0
  AttachSerializableXact(fps->serializable_xact_handle);
1568
1569
  /*
1570
   * We've initialized all of our state now; nothing should change
1571
   * hereafter.
1572
   */
1573
0
  InitializingParallelWorker = false;
1574
0
  EnterParallelMode();
1575
1576
  /*
1577
   * Time to do the real work: invoke the caller-supplied code.
1578
   */
1579
0
  entrypt(seg, toc);
1580
1581
  /* Must exit parallel mode to pop active snapshot. */
1582
0
  ExitParallelMode();
1583
1584
  /* Must pop active snapshot so snapmgr.c doesn't complain. */
1585
0
  PopActiveSnapshot();
1586
1587
  /* Shut down the parallel-worker transaction. */
1588
0
  EndParallelWorkerTransaction();
1589
1590
  /* Detach from the per-session DSM segment. */
1591
0
  DetachSession();
1592
1593
  /* Report success. */
1594
0
  pq_putmessage(PqMsg_Terminate, NULL, 0);
1595
0
}
1596
1597
/*
1598
 * Update shared memory with the ending location of the last WAL record we
1599
 * wrote, if it's greater than the value already stored there.
1600
 */
1601
void
1602
ParallelWorkerReportLastRecEnd(XLogRecPtr last_xlog_end)
1603
0
{
1604
0
  FixedParallelState *fps = MyFixedParallelState;
1605
1606
0
  Assert(fps != NULL);
1607
0
  pg_atomic_monotonic_advance_u64(&fps->last_xlog_end, last_xlog_end);
1608
0
}
1609
1610
/*
1611
 * Make sure the leader tries to read from our error queue one more time.
1612
 * This guards against the case where we exit uncleanly without sending an
1613
 * ErrorResponse to the leader, for example because some code calls proc_exit
1614
 * directly.
1615
 *
1616
 * Also explicitly detach from dsm segment so that subsystems using
1617
 * on_dsm_detach() have a chance to send stats before the stats subsystem is
1618
 * shut down as part of a before_shmem_exit() hook.
1619
 *
1620
 * One might think this could instead be solved by carefully ordering the
1621
 * attaching to dsm segments, so that the pgstats segments get detached from
1622
 * later than the parallel query one. That turns out to not work because the
1623
 * stats hash might need to grow which can cause new segments to be allocated,
1624
 * which then will be detached from earlier.
1625
 */
1626
static void
1627
ParallelWorkerShutdown(int code, Datum arg)
1628
0
{
1629
0
  SendProcSignal(ParallelLeaderPid,
1630
0
           PROCSIG_PARALLEL_MESSAGE,
1631
0
           ParallelLeaderProcNumber);
1632
1633
0
  dsm_detach((dsm_segment *) DatumGetPointer(arg));
1634
0
}
1635
1636
/*
1637
 * Look up (and possibly load) a parallel worker entry point function.
1638
 *
1639
 * For functions contained in the core code, we use library name "postgres"
1640
 * and consult the InternalParallelWorkers array.  External functions are
1641
 * looked up, and loaded if necessary, using load_external_function().
1642
 *
1643
 * The point of this is to pass function names as strings across process
1644
 * boundaries.  We can't pass actual function addresses because of the
1645
 * possibility that the function has been loaded at a different address
1646
 * in a different process.  This is obviously a hazard for functions in
1647
 * loadable libraries, but it can happen even for functions in the core code
1648
 * on platforms using EXEC_BACKEND (e.g., Windows).
1649
 *
1650
 * At some point it might be worthwhile to get rid of InternalParallelWorkers[]
1651
 * in favor of applying load_external_function() for core functions too;
1652
 * but that raises portability issues that are not worth addressing now.
1653
 */
1654
static parallel_worker_main_type
1655
LookupParallelWorkerFunction(const char *libraryname, const char *funcname)
1656
0
{
1657
  /*
1658
   * If the function is to be loaded from postgres itself, search the
1659
   * InternalParallelWorkers array.
1660
   */
1661
0
  if (strcmp(libraryname, "postgres") == 0)
1662
0
  {
1663
0
    for (size_t i = 0; i < lengthof(InternalParallelWorkers); i++)
1664
0
    {
1665
0
      if (strcmp(InternalParallelWorkers[i].fn_name, funcname) == 0)
1666
0
        return InternalParallelWorkers[i].fn_addr;
1667
0
    }
1668
1669
    /* We can only reach this by programming error. */
1670
0
    elog(ERROR, "internal function \"%s\" not found", funcname);
1671
0
  }
1672
1673
  /* Otherwise load from external library. */
1674
0
  return (parallel_worker_main_type)
1675
0
    load_external_function(libraryname, funcname, true, NULL);
1676
0
}