mirror of
https://github.com/postgres/postgres.git
synced 2026-03-09 17:50:43 -04:00
If we failed to fork a worker process, or create a communication pipe
for one, WaitForTerminatingWorkers would suffer an assertion failure
if assert-enabled, otherwise crash or go into an infinite loop. This
was a consequence of not accounting for the startup condition where
we've not yet forked all the workers.
The original bug was that ParallelBackupStart would set workerStatus to
WRKR_IDLE before it had successfully forked a worker. I made things
worse in commit b7b8cc0cf by not understanding the undocumented fact
that the WRKR_TERMINATED state was also meant to represent the case
where a worker hadn't been started yet: I changed enum T_WorkerStatus
so that *all* the worker slots were initially in WRKR_IDLE state. But
this wasn't any more broken in practice, since even one slot in the
wrong state would keep WaitForTerminatingWorkers from terminating.
In v10 and later, introduce an explicit T_WorkerStatus value for
worker-not-started, in hopes of preventing future oversights of the
same ilk. Before that, just document that WRKR_TERMINATED is supposed
to cover that case (partly because it wasn't actively broken, and
partly because the enum is exposed outside parallel.c in those branches,
so there's microscopically more risk involved in changing it).
In all branches, introduce a WORKER_IS_RUNNING status test macro
to hide which T_WorkerStatus values mean that, and be more careful
not to access ParallelSlot fields till we're sure they're valid.
Per report from Vignesh C, though this is my patch not his.
Back-patch to all supported branches.
Discussion: https://postgr.es/m/CALDaNm1Luv-E3sarR+-unz-BjchquHHyfP+YC+2FS2pt_J+wxg@mail.gmail.com
90 lines
2.3 KiB
C
90 lines
2.3 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* parallel.h
|
|
*
|
|
* Parallel support header file for the pg_dump archiver
|
|
*
|
|
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
* The author is not responsible for loss or damages that may
|
|
* result from its use.
|
|
*
|
|
* IDENTIFICATION
|
|
* src/bin/pg_dump/parallel.h
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
#ifndef PG_DUMP_PARALLEL_H
|
|
#define PG_DUMP_PARALLEL_H
|
|
|
|
#include "pg_backup_archiver.h"
|
|
|
|
typedef enum
|
|
{
|
|
WRKR_TERMINATED = 0,
|
|
WRKR_IDLE,
|
|
WRKR_WORKING,
|
|
WRKR_FINISHED
|
|
} T_WorkerStatus;
|
|
|
|
#define WORKER_IS_RUNNING(workerStatus) \
|
|
((workerStatus) != WRKR_TERMINATED)
|
|
|
|
/* Arguments needed for a worker process */
|
|
typedef struct ParallelArgs
|
|
{
|
|
ArchiveHandle *AH;
|
|
TocEntry *te;
|
|
} ParallelArgs;
|
|
|
|
/* State for each parallel activity slot */
|
|
typedef struct ParallelSlot
|
|
{
|
|
ParallelArgs *args;
|
|
T_WorkerStatus workerStatus;
|
|
int status;
|
|
int pipeRead; /* master's end of the pipes */
|
|
int pipeWrite;
|
|
int pipeRevRead; /* child's end of the pipes */
|
|
int pipeRevWrite;
|
|
#ifdef WIN32
|
|
uintptr_t hThread;
|
|
unsigned int threadId;
|
|
#else
|
|
pid_t pid;
|
|
#endif
|
|
} ParallelSlot;
|
|
|
|
#define NO_SLOT (-1)
|
|
|
|
typedef struct ParallelState
|
|
{
|
|
int numWorkers;
|
|
ParallelSlot *parallelSlot;
|
|
} ParallelState;
|
|
|
|
#ifdef WIN32
|
|
extern bool parallel_init_done;
|
|
extern DWORD mainThreadId;
|
|
#endif
|
|
|
|
extern void init_parallel_dump_utils(void);
|
|
|
|
extern int GetIdleWorker(ParallelState *pstate);
|
|
extern bool IsEveryWorkerIdle(ParallelState *pstate);
|
|
extern void ListenToWorkers(ArchiveHandle *AH, ParallelState *pstate, bool do_wait);
|
|
extern int ReapWorkerStatus(ParallelState *pstate, int *status);
|
|
extern void EnsureIdleWorker(ArchiveHandle *AH, ParallelState *pstate);
|
|
extern void EnsureWorkersFinished(ArchiveHandle *AH, ParallelState *pstate);
|
|
|
|
extern ParallelState *ParallelBackupStart(ArchiveHandle *AH);
|
|
extern void DispatchJobForTocEntry(ArchiveHandle *AH,
|
|
ParallelState *pstate,
|
|
TocEntry *te, T_Action act);
|
|
extern void ParallelBackupEnd(ArchiveHandle *AH, ParallelState *pstate);
|
|
|
|
extern void set_archive_cancel_info(ArchiveHandle *AH, PGconn *conn);
|
|
|
|
#endif /* PG_DUMP_PARALLEL_H */
|