2013-03-24 16:27:20 +01:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* parallel.h
|
|
|
|
*
|
Redesign parallel dump/restore's wait-for-workers logic.
The ListenToWorkers/ReapWorkerStatus APIs were messy and hard to use.
Instead, make DispatchJobForTocEntry register a callback function that
will take care of state cleanup, doing whatever had been done by the caller
of ReapWorkerStatus in the old design. (This callback is essentially just
the old mark_work_done function in the restore case, and a trivial test for
worker failure in the dump case.) Then we can have ListenToWorkers call
the callback immediately on receipt of a status message, and return the
worker to WRKR_IDLE state; so the WRKR_FINISHED state goes away.
This allows us to design a unified wait-for-worker-messages loop:
WaitForWorkers replaces EnsureIdleWorker and EnsureWorkersFinished as well
as the mess in restore_toc_entries_parallel. Also, we no longer need the
fragile API spec that the caller of DispatchJobForTocEntry is responsible
for ensuring there's an idle worker, since DispatchJobForTocEntry can just
wait until there is one.
In passing, I got rid of the ParallelArgs struct, which was a net negative
in terms of notational verboseness, and didn't seem to be providing any
noticeable amount of abstraction either.
Tom Lane, reviewed by Kevin Grittner
Discussion: <1188.1464544443@sss.pgh.pa.us>
2016-09-27 19:22:39 +02:00
|
|
|
* Parallel support for pg_dump and pg_restore
|
2013-03-24 16:27:20 +01:00
|
|
|
*
|
2023-01-02 21:00:37 +01:00
|
|
|
* Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
|
2013-03-24 16:27:20 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
|
|
|
* src/bin/pg_dump/parallel.h
|
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
2013-03-27 17:10:40 +01:00
|
|
|
#ifndef PG_DUMP_PARALLEL_H
|
|
|
|
#define PG_DUMP_PARALLEL_H
|
|
|
|
|
2021-07-24 12:05:14 +02:00
|
|
|
#include <limits.h>
|
|
|
|
|
2014-10-14 20:00:55 +02:00
|
|
|
#include "pg_backup_archiver.h"
|
2013-03-24 16:27:20 +01:00
|
|
|
|
2020-06-14 23:22:47 +02:00
|
|
|
/* Function to call in leader process on completion of a worker task */
|
Redesign parallel dump/restore's wait-for-workers logic.
The ListenToWorkers/ReapWorkerStatus APIs were messy and hard to use.
Instead, make DispatchJobForTocEntry register a callback function that
will take care of state cleanup, doing whatever had been done by the caller
of ReapWorkerStatus in the old design. (This callback is essentially just
the old mark_work_done function in the restore case, and a trivial test for
worker failure in the dump case.) Then we can have ListenToWorkers call
the callback immediately on receipt of a status message, and return the
worker to WRKR_IDLE state; so the WRKR_FINISHED state goes away.
This allows us to design a unified wait-for-worker-messages loop:
WaitForWorkers replaces EnsureIdleWorker and EnsureWorkersFinished as well
as the mess in restore_toc_entries_parallel. Also, we no longer need the
fragile API spec that the caller of DispatchJobForTocEntry is responsible
for ensuring there's an idle worker, since DispatchJobForTocEntry can just
wait until there is one.
In passing, I got rid of the ParallelArgs struct, which was a net negative
in terms of notational verboseness, and didn't seem to be providing any
noticeable amount of abstraction either.
Tom Lane, reviewed by Kevin Grittner
Discussion: <1188.1464544443@sss.pgh.pa.us>
2016-09-27 19:22:39 +02:00
|
|
|
typedef void (*ParallelCompletionPtr) (ArchiveHandle *AH,
|
|
|
|
TocEntry *te,
|
|
|
|
int status,
|
|
|
|
void *callback_data);
|
|
|
|
|
|
|
|
/* Wait options for WaitForWorkers */
|
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
WFW_NO_WAIT,
|
|
|
|
WFW_GOT_STATUS,
|
|
|
|
WFW_ONE_IDLE,
|
|
|
|
WFW_ALL_IDLE
|
|
|
|
} WFW_WaitOption;
|
|
|
|
|
2021-07-24 11:35:03 +02:00
|
|
|
/*
|
|
|
|
* Maximum number of parallel jobs allowed.
|
|
|
|
*
|
|
|
|
* On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually)
|
|
|
|
* parallel jobs because that's the maximum limit for the
|
|
|
|
* WaitForMultipleObjects() call.
|
|
|
|
*/
|
|
|
|
#ifdef WIN32
|
|
|
|
#define PG_MAX_JOBS MAXIMUM_WAIT_OBJECTS
|
|
|
|
#else
|
|
|
|
#define PG_MAX_JOBS INT_MAX
|
|
|
|
#endif
|
|
|
|
|
2016-09-27 20:29:12 +02:00
|
|
|
/* ParallelSlot is an opaque struct known only within parallel.c */
|
|
|
|
typedef struct ParallelSlot ParallelSlot;
|
2013-03-24 16:27:20 +01:00
|
|
|
|
Redesign parallel dump/restore's wait-for-workers logic.
The ListenToWorkers/ReapWorkerStatus APIs were messy and hard to use.
Instead, make DispatchJobForTocEntry register a callback function that
will take care of state cleanup, doing whatever had been done by the caller
of ReapWorkerStatus in the old design. (This callback is essentially just
the old mark_work_done function in the restore case, and a trivial test for
worker failure in the dump case.) Then we can have ListenToWorkers call
the callback immediately on receipt of a status message, and return the
worker to WRKR_IDLE state; so the WRKR_FINISHED state goes away.
This allows us to design a unified wait-for-worker-messages loop:
WaitForWorkers replaces EnsureIdleWorker and EnsureWorkersFinished as well
as the mess in restore_toc_entries_parallel. Also, we no longer need the
fragile API spec that the caller of DispatchJobForTocEntry is responsible
for ensuring there's an idle worker, since DispatchJobForTocEntry can just
wait until there is one.
In passing, I got rid of the ParallelArgs struct, which was a net negative
in terms of notational verboseness, and didn't seem to be providing any
noticeable amount of abstraction either.
Tom Lane, reviewed by Kevin Grittner
Discussion: <1188.1464544443@sss.pgh.pa.us>
2016-09-27 19:22:39 +02:00
|
|
|
/* Overall state for parallel.c */
|
2013-03-24 16:27:20 +01:00
|
|
|
typedef struct ParallelState
|
|
|
|
{
|
Redesign parallel dump/restore's wait-for-workers logic.
The ListenToWorkers/ReapWorkerStatus APIs were messy and hard to use.
Instead, make DispatchJobForTocEntry register a callback function that
will take care of state cleanup, doing whatever had been done by the caller
of ReapWorkerStatus in the old design. (This callback is essentially just
the old mark_work_done function in the restore case, and a trivial test for
worker failure in the dump case.) Then we can have ListenToWorkers call
the callback immediately on receipt of a status message, and return the
worker to WRKR_IDLE state; so the WRKR_FINISHED state goes away.
This allows us to design a unified wait-for-worker-messages loop:
WaitForWorkers replaces EnsureIdleWorker and EnsureWorkersFinished as well
as the mess in restore_toc_entries_parallel. Also, we no longer need the
fragile API spec that the caller of DispatchJobForTocEntry is responsible
for ensuring there's an idle worker, since DispatchJobForTocEntry can just
wait until there is one.
In passing, I got rid of the ParallelArgs struct, which was a net negative
in terms of notational verboseness, and didn't seem to be providing any
noticeable amount of abstraction either.
Tom Lane, reviewed by Kevin Grittner
Discussion: <1188.1464544443@sss.pgh.pa.us>
2016-09-27 19:22:39 +02:00
|
|
|
int numWorkers; /* allowed number of workers */
|
2016-09-27 20:29:12 +02:00
|
|
|
/* these arrays have numWorkers entries, one per worker: */
|
|
|
|
TocEntry **te; /* item being worked on, or NULL */
|
|
|
|
ParallelSlot *parallelSlot; /* private info about each worker */
|
2013-03-24 16:27:20 +01:00
|
|
|
} ParallelState;
|
|
|
|
|
2013-03-27 17:10:40 +01:00
|
|
|
#ifdef WIN32
|
|
|
|
extern bool parallel_init_done;
|
|
|
|
extern DWORD mainThreadId;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
extern void init_parallel_dump_utils(void);
|
|
|
|
|
2013-03-24 16:27:20 +01:00
|
|
|
extern bool IsEveryWorkerIdle(ParallelState *pstate);
|
Redesign parallel dump/restore's wait-for-workers logic.
The ListenToWorkers/ReapWorkerStatus APIs were messy and hard to use.
Instead, make DispatchJobForTocEntry register a callback function that
will take care of state cleanup, doing whatever had been done by the caller
of ReapWorkerStatus in the old design. (This callback is essentially just
the old mark_work_done function in the restore case, and a trivial test for
worker failure in the dump case.) Then we can have ListenToWorkers call
the callback immediately on receipt of a status message, and return the
worker to WRKR_IDLE state; so the WRKR_FINISHED state goes away.
This allows us to design a unified wait-for-worker-messages loop:
WaitForWorkers replaces EnsureIdleWorker and EnsureWorkersFinished as well
as the mess in restore_toc_entries_parallel. Also, we no longer need the
fragile API spec that the caller of DispatchJobForTocEntry is responsible
for ensuring there's an idle worker, since DispatchJobForTocEntry can just
wait until there is one.
In passing, I got rid of the ParallelArgs struct, which was a net negative
in terms of notational verboseness, and didn't seem to be providing any
noticeable amount of abstraction either.
Tom Lane, reviewed by Kevin Grittner
Discussion: <1188.1464544443@sss.pgh.pa.us>
2016-09-27 19:22:39 +02:00
|
|
|
extern void WaitForWorkers(ArchiveHandle *AH, ParallelState *pstate,
|
|
|
|
WFW_WaitOption mode);
|
2013-03-24 16:27:20 +01:00
|
|
|
|
2016-01-13 23:48:33 +01:00
|
|
|
extern ParallelState *ParallelBackupStart(ArchiveHandle *AH);
|
2014-10-14 20:00:55 +02:00
|
|
|
extern void DispatchJobForTocEntry(ArchiveHandle *AH,
|
2013-03-24 16:27:20 +01:00
|
|
|
ParallelState *pstate,
|
Redesign parallel dump/restore's wait-for-workers logic.
The ListenToWorkers/ReapWorkerStatus APIs were messy and hard to use.
Instead, make DispatchJobForTocEntry register a callback function that
will take care of state cleanup, doing whatever had been done by the caller
of ReapWorkerStatus in the old design. (This callback is essentially just
the old mark_work_done function in the restore case, and a trivial test for
worker failure in the dump case.) Then we can have ListenToWorkers call
the callback immediately on receipt of a status message, and return the
worker to WRKR_IDLE state; so the WRKR_FINISHED state goes away.
This allows us to design a unified wait-for-worker-messages loop:
WaitForWorkers replaces EnsureIdleWorker and EnsureWorkersFinished as well
as the mess in restore_toc_entries_parallel. Also, we no longer need the
fragile API spec that the caller of DispatchJobForTocEntry is responsible
for ensuring there's an idle worker, since DispatchJobForTocEntry can just
wait until there is one.
In passing, I got rid of the ParallelArgs struct, which was a net negative
in terms of notational verboseness, and didn't seem to be providing any
noticeable amount of abstraction either.
Tom Lane, reviewed by Kevin Grittner
Discussion: <1188.1464544443@sss.pgh.pa.us>
2016-09-27 19:22:39 +02:00
|
|
|
TocEntry *te,
|
|
|
|
T_Action act,
|
|
|
|
ParallelCompletionPtr callback,
|
|
|
|
void *callback_data);
|
2014-10-14 20:00:55 +02:00
|
|
|
extern void ParallelBackupEnd(ArchiveHandle *AH, ParallelState *pstate);
|
2013-03-27 17:10:40 +01:00
|
|
|
|
Redesign handling of SIGTERM/control-C in parallel pg_dump/pg_restore.
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>
2016-06-02 19:27:53 +02:00
|
|
|
extern void set_archive_cancel_info(ArchiveHandle *AH, PGconn *conn);
|
2013-03-27 17:10:40 +01:00
|
|
|
|
|
|
|
#endif /* PG_DUMP_PARALLEL_H */
|