mirror of
https://github.com/postgres/postgres.git
synced 2025-05-24 00:03:23 -04:00
Formerly, Unix builds of pg_dump/pg_restore would trap SIGINT and similar signals and set a flag that was tested in various data-transfer loops. This was prone to errors of omission (cf commit 3c8aa6654); and even if the client-side response was prompt, we did nothing that would cause long-running SQL commands (e.g. CREATE INDEX) to terminate early. Also, the master process would effectively do nothing at all upon receipt of SIGINT; the only reason it seemed to work was that in typical scenarios the signal would also be delivered to the child processes. We should support termination when a signal is delivered only to the master process, though. Windows builds had no console interrupt handler, so they would just fall over immediately at control-C, again leaving long-running SQL commands to finish unmolested. To fix, remove the flag-checking approach altogether. Instead, allow the Unix signal handler to send a cancel request directly and then exit(1). In the master process, also have it forward the signal to the children. On Windows, add a console interrupt handler that behaves approximately the same. The main difference is that a single execution of the Windows handler can send all the cancel requests since all the info is available in one process, whereas on Unix each process sends a cancel only for its own database connection. In passing, fix an old problem that DisconnectDatabase tends to send a cancel request before exiting a parallel worker, even if nothing went wrong. This is at least a waste of cycles, and could lead to unexpected log messages, or maybe even data loss if it happened in pg_restore (though in the current code the problem seems to affect only pg_dump). The cause was that after a COPY step, pg_dump was leaving libpq in PGASYNC_BUSY state, causing PQtransactionStatus() to report PQTRANS_ACTIVE. That's normally harmless because the next PQexec() will silently clear the PGASYNC_BUSY state; but in a parallel worker we might exit without any additional SQL commands after a COPY step. So add an extra PQgetResult() call after a COPY to allow libpq to return to PGASYNC_IDLE state. This is a bug fix, IMO, so back-patch to 9.3 where parallel dump/restore were introduced. Thanks to Kyotaro Horiguchi for Windows testing and code suggestions. Original-Patch: <7005.1464657274@sss.pgh.pa.us> Discussion: <20160602.174941.256342236.horiguchi.kyotaro@lab.ntt.co.jp>
88 lines
2.2 KiB
C
88 lines
2.2 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;
|
|
|
|
/* 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 */
|