mirror of
https://github.com/postgres/postgres.git
synced 2025-06-23 14:01:44 +03:00
Move some pg_dump function around.
Move functions used only by pg_dump and pg_restore from dumputils.c to a new file, pg_backup_utils.c. dumputils.c is linked into psql and some programs in bin/scripts, so it seems good to keep it slim. The parallel functionality is moved to parallel.c, as is exit_horribly, because the interesting code in exit_horribly is parallel-related. This refactoring gets rid of the on_exit_msg_func function pointer. It was problematic, because a modern gcc version with -Wmissing-format-attribute complained if it wasn't marked with PF_PRINTF_ATTRIBUTE, but the ancient gcc version that Tom Lane's old HP-UX box has didn't accept that attribute on a function pointer, and gave an error. We still use a similar function pointer trick for getLocalPQBuffer() function, to use a thread-local version of that in parallel mode on Windows, but that dodges the problem because it doesn't take printf-like arguments.
This commit is contained in:
@ -19,8 +19,8 @@ include $(top_builddir)/src/Makefile.global
|
|||||||
override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS)
|
override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS)
|
||||||
|
|
||||||
OBJS= pg_backup_archiver.o pg_backup_db.o pg_backup_custom.o \
|
OBJS= pg_backup_archiver.o pg_backup_db.o pg_backup_custom.o \
|
||||||
pg_backup_null.o pg_backup_tar.o parallel.o \
|
pg_backup_null.o pg_backup_tar.o pg_backup_directory.o \
|
||||||
pg_backup_directory.o dumputils.o compress_io.o $(WIN32RES)
|
pg_backup_utils.o parallel.o compress_io.o dumputils.o $(WIN32RES)
|
||||||
|
|
||||||
KEYWRDOBJS = keywords.o kwlookup.o
|
KEYWRDOBJS = keywords.o kwlookup.o
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#include "pg_backup_archiver.h"
|
#include "pg_backup_archiver.h"
|
||||||
|
#include "pg_backup_utils.h"
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "compress_io.h"
|
#include "compress_io.h"
|
||||||
#include "dumputils.h"
|
#include "pg_backup_utils.h"
|
||||||
#include "parallel.h"
|
#include "parallel.h"
|
||||||
|
|
||||||
/*----------------------
|
/*----------------------
|
||||||
|
@ -25,21 +25,6 @@
|
|||||||
extern const ScanKeyword FEScanKeywords[];
|
extern const ScanKeyword FEScanKeywords[];
|
||||||
extern const int NumFEScanKeywords;
|
extern const int NumFEScanKeywords;
|
||||||
|
|
||||||
/* Globals exported by this file */
|
|
||||||
int quote_all_identifiers = 0;
|
|
||||||
const char *progname = NULL;
|
|
||||||
|
|
||||||
#define MAX_ON_EXIT_NICELY 20
|
|
||||||
|
|
||||||
static struct
|
|
||||||
{
|
|
||||||
on_exit_nicely_callback function;
|
|
||||||
void *arg;
|
|
||||||
} on_exit_nicely_list[MAX_ON_EXIT_NICELY];
|
|
||||||
|
|
||||||
static int on_exit_nicely_index;
|
|
||||||
void (*on_exit_msg_func) (const char *modulename, const char *fmt, va_list ap) = vwrite_msg;
|
|
||||||
|
|
||||||
#define supports_grant_options(version) ((version) >= 70400)
|
#define supports_grant_options(version) ((version) >= 70400)
|
||||||
|
|
||||||
static bool parseAclItem(const char *item, const char *type,
|
static bool parseAclItem(const char *item, const char *type,
|
||||||
@ -49,68 +34,24 @@ static bool parseAclItem(const char *item, const char *type,
|
|||||||
static char *copyAclUserName(PQExpBuffer output, char *input);
|
static char *copyAclUserName(PQExpBuffer output, char *input);
|
||||||
static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
|
static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
|
||||||
const char *subname);
|
const char *subname);
|
||||||
static PQExpBuffer getThreadLocalPQExpBuffer(void);
|
static PQExpBuffer defaultGetLocalPQExpBuffer(void);
|
||||||
|
|
||||||
#ifdef WIN32
|
/* Globals exported by this file */
|
||||||
static void shutdown_parallel_dump_utils(int code, void *unused);
|
int quote_all_identifiers = 0;
|
||||||
static bool parallel_init_done = false;
|
PQExpBuffer (*getLocalPQExpBuffer) (void) = defaultGetLocalPQExpBuffer;
|
||||||
static DWORD tls_index;
|
|
||||||
static DWORD mainThreadId;
|
|
||||||
|
|
||||||
static void
|
|
||||||
shutdown_parallel_dump_utils(int code, void *unused)
|
|
||||||
{
|
|
||||||
/* Call the cleanup function only from the main thread */
|
|
||||||
if (mainThreadId == GetCurrentThreadId())
|
|
||||||
WSACleanup();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void
|
|
||||||
init_parallel_dump_utils(void)
|
|
||||||
{
|
|
||||||
#ifdef WIN32
|
|
||||||
if (!parallel_init_done)
|
|
||||||
{
|
|
||||||
WSADATA wsaData;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
tls_index = TlsAlloc();
|
|
||||||
mainThreadId = GetCurrentThreadId();
|
|
||||||
err = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
|
||||||
if (err != 0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, _("WSAStartup failed: %d\n"), err);
|
|
||||||
exit_nicely(1);
|
|
||||||
}
|
|
||||||
on_exit_nicely(shutdown_parallel_dump_utils, NULL);
|
|
||||||
parallel_init_done = true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Non-reentrant but reduces memory leakage. (On Windows the memory leakage
|
* Returns a temporary PQExpBuffer, valid until the next call to the function.
|
||||||
* will be one buffer per thread, which is at least better than one per call).
|
* This is used by fmtId and fmtQualifiedId.
|
||||||
|
*
|
||||||
|
* Non-reentrant and non-thread-safe but reduces memory leakage. You can
|
||||||
|
* replace this with a custom version by setting the getLocalPQExpBuffer
|
||||||
|
* function pointer.
|
||||||
*/
|
*/
|
||||||
static PQExpBuffer
|
static PQExpBuffer
|
||||||
getThreadLocalPQExpBuffer(void)
|
defaultGetLocalPQExpBuffer(void)
|
||||||
{
|
{
|
||||||
/*
|
static PQExpBuffer id_return = NULL;
|
||||||
* The Tls code goes awry if we use a static var, so we provide for both
|
|
||||||
* static and auto, and omit any use of the static var when using Tls.
|
|
||||||
*/
|
|
||||||
static PQExpBuffer s_id_return = NULL;
|
|
||||||
PQExpBuffer id_return;
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
if (parallel_init_done)
|
|
||||||
id_return = (PQExpBuffer) TlsGetValue(tls_index); /* 0 when not set */
|
|
||||||
else
|
|
||||||
id_return = s_id_return;
|
|
||||||
#else
|
|
||||||
id_return = s_id_return;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (id_return) /* first time through? */
|
if (id_return) /* first time through? */
|
||||||
{
|
{
|
||||||
@ -121,15 +62,6 @@ getThreadLocalPQExpBuffer(void)
|
|||||||
{
|
{
|
||||||
/* new buffer */
|
/* new buffer */
|
||||||
id_return = createPQExpBuffer();
|
id_return = createPQExpBuffer();
|
||||||
#ifdef WIN32
|
|
||||||
if (parallel_init_done)
|
|
||||||
TlsSetValue(tls_index, id_return);
|
|
||||||
else
|
|
||||||
s_id_return = id_return;
|
|
||||||
#else
|
|
||||||
s_id_return = id_return;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return id_return;
|
return id_return;
|
||||||
@ -144,7 +76,7 @@ getThreadLocalPQExpBuffer(void)
|
|||||||
const char *
|
const char *
|
||||||
fmtId(const char *rawid)
|
fmtId(const char *rawid)
|
||||||
{
|
{
|
||||||
PQExpBuffer id_return = getThreadLocalPQExpBuffer();
|
PQExpBuffer id_return = getLocalPQExpBuffer();
|
||||||
|
|
||||||
const char *cp;
|
const char *cp;
|
||||||
bool need_quotes = false;
|
bool need_quotes = false;
|
||||||
@ -238,7 +170,7 @@ fmtQualifiedId(int remoteVersion, const char *schema, const char *id)
|
|||||||
}
|
}
|
||||||
appendPQExpBuffer(lcl_pqexp, "%s", fmtId(id));
|
appendPQExpBuffer(lcl_pqexp, "%s", fmtId(id));
|
||||||
|
|
||||||
id_return = getThreadLocalPQExpBuffer();
|
id_return = getLocalPQExpBuffer();
|
||||||
|
|
||||||
appendPQExpBuffer(id_return, "%s", lcl_pqexp->data);
|
appendPQExpBuffer(id_return, "%s", lcl_pqexp->data);
|
||||||
destroyPQExpBuffer(lcl_pqexp);
|
destroyPQExpBuffer(lcl_pqexp);
|
||||||
@ -1278,118 +1210,6 @@ emitShSecLabels(PGconn *conn, PGresult *res, PQExpBuffer buffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Parse a --section=foo command line argument.
|
|
||||||
*
|
|
||||||
* Set or update the bitmask in *dumpSections according to arg.
|
|
||||||
* dumpSections is initialised as DUMP_UNSECTIONED by pg_dump and
|
|
||||||
* pg_restore so they can know if this has even been called.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
set_dump_section(const char *arg, int *dumpSections)
|
|
||||||
{
|
|
||||||
/* if this is the first call, clear all the bits */
|
|
||||||
if (*dumpSections == DUMP_UNSECTIONED)
|
|
||||||
*dumpSections = 0;
|
|
||||||
|
|
||||||
if (strcmp(arg, "pre-data") == 0)
|
|
||||||
*dumpSections |= DUMP_PRE_DATA;
|
|
||||||
else if (strcmp(arg, "data") == 0)
|
|
||||||
*dumpSections |= DUMP_DATA;
|
|
||||||
else if (strcmp(arg, "post-data") == 0)
|
|
||||||
*dumpSections |= DUMP_POST_DATA;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fprintf(stderr, _("%s: unrecognized section name: \"%s\"\n"),
|
|
||||||
progname, arg);
|
|
||||||
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
|
||||||
progname);
|
|
||||||
exit_nicely(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Write a printf-style message to stderr.
|
|
||||||
*
|
|
||||||
* The program name is prepended, if "progname" has been set.
|
|
||||||
* Also, if modulename isn't NULL, that's included too.
|
|
||||||
* Note that we'll try to translate the modulename and the fmt string.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
write_msg(const char *modulename, const char *fmt,...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
vwrite_msg(modulename, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* As write_msg, but pass a va_list not variable arguments.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
vwrite_msg(const char *modulename, const char *fmt, va_list ap)
|
|
||||||
{
|
|
||||||
if (progname)
|
|
||||||
{
|
|
||||||
if (modulename)
|
|
||||||
fprintf(stderr, "%s: [%s] ", progname, _(modulename));
|
|
||||||
else
|
|
||||||
fprintf(stderr, "%s: ", progname);
|
|
||||||
}
|
|
||||||
vfprintf(stderr, _(fmt), ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Fail and die, with a message to stderr. Parameters as for write_msg.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
exit_horribly(const char *modulename, const char *fmt,...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
on_exit_msg_func(modulename, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
exit_nicely(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Register a callback to be run when exit_nicely is invoked. */
|
|
||||||
void
|
|
||||||
on_exit_nicely(on_exit_nicely_callback function, void *arg)
|
|
||||||
{
|
|
||||||
if (on_exit_nicely_index >= MAX_ON_EXIT_NICELY)
|
|
||||||
exit_horribly(NULL, "out of on_exit_nicely slots\n");
|
|
||||||
on_exit_nicely_list[on_exit_nicely_index].function = function;
|
|
||||||
on_exit_nicely_list[on_exit_nicely_index].arg = arg;
|
|
||||||
on_exit_nicely_index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Run accumulated on_exit_nicely callbacks in reverse order and then exit
|
|
||||||
* quietly. This needs to be thread-safe.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
exit_nicely(int code)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = on_exit_nicely_index - 1; i >= 0; i--)
|
|
||||||
(*on_exit_nicely_list[i].function) (code,
|
|
||||||
on_exit_nicely_list[i].arg);
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
if (parallel_init_done && GetCurrentThreadId() != mainThreadId)
|
|
||||||
ExitThread(code);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
exit(code);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
simple_string_list_append(SimpleStringList *list, const char *val)
|
simple_string_list_append(SimpleStringList *list, const char *val)
|
||||||
{
|
{
|
||||||
|
@ -19,14 +19,6 @@
|
|||||||
#include "libpq-fe.h"
|
#include "libpq-fe.h"
|
||||||
#include "pqexpbuffer.h"
|
#include "pqexpbuffer.h"
|
||||||
|
|
||||||
typedef enum /* bits returned by set_dump_section */
|
|
||||||
{
|
|
||||||
DUMP_PRE_DATA = 0x01,
|
|
||||||
DUMP_DATA = 0x02,
|
|
||||||
DUMP_POST_DATA = 0x04,
|
|
||||||
DUMP_UNSECTIONED = 0xff
|
|
||||||
} DumpSections;
|
|
||||||
|
|
||||||
typedef struct SimpleStringListCell
|
typedef struct SimpleStringListCell
|
||||||
{
|
{
|
||||||
struct SimpleStringListCell *next;
|
struct SimpleStringListCell *next;
|
||||||
@ -40,14 +32,9 @@ typedef struct SimpleStringList
|
|||||||
} SimpleStringList;
|
} SimpleStringList;
|
||||||
|
|
||||||
|
|
||||||
typedef void (*on_exit_nicely_callback) (int code, void *arg);
|
|
||||||
|
|
||||||
extern int quote_all_identifiers;
|
extern int quote_all_identifiers;
|
||||||
extern const char *progname;
|
extern PQExpBuffer (*getLocalPQExpBuffer) (void);
|
||||||
extern void (*on_exit_msg_func) (const char *modulename, const char *fmt, va_list ap)
|
|
||||||
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 0)));
|
|
||||||
|
|
||||||
extern void init_parallel_dump_utils(void);
|
|
||||||
extern const char *fmtId(const char *identifier);
|
extern const char *fmtId(const char *identifier);
|
||||||
extern const char *fmtQualifiedId(int remoteVersion,
|
extern const char *fmtQualifiedId(int remoteVersion,
|
||||||
const char *schema, const char *id);
|
const char *schema, const char *id);
|
||||||
@ -79,17 +66,6 @@ extern void buildShSecLabelQuery(PGconn *conn, const char *catalog_name,
|
|||||||
extern void emitShSecLabels(PGconn *conn, PGresult *res,
|
extern void emitShSecLabels(PGconn *conn, PGresult *res,
|
||||||
PQExpBuffer buffer, const char *target, const char *objname);
|
PQExpBuffer buffer, const char *target, const char *objname);
|
||||||
extern void set_dump_section(const char *arg, int *dumpSections);
|
extern void set_dump_section(const char *arg, int *dumpSections);
|
||||||
extern void
|
|
||||||
write_msg(const char *modulename, const char *fmt,...)
|
|
||||||
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
|
|
||||||
extern void
|
|
||||||
vwrite_msg(const char *modulename, const char *fmt, va_list ap)
|
|
||||||
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 0)));
|
|
||||||
extern void
|
|
||||||
exit_horribly(const char *modulename, const char *fmt,...)
|
|
||||||
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3), noreturn));
|
|
||||||
extern void on_exit_nicely(on_exit_nicely_callback function, void *arg);
|
|
||||||
extern void exit_nicely(int code) __attribute__((noreturn));
|
|
||||||
|
|
||||||
extern void simple_string_list_append(SimpleStringList *list, const char *val);
|
extern void simple_string_list_append(SimpleStringList *list, const char *val);
|
||||||
extern bool simple_string_list_member(SimpleStringList *list, const char *val);
|
extern bool simple_string_list_member(SimpleStringList *list, const char *val);
|
||||||
|
@ -16,9 +16,9 @@
|
|||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "pg_backup_db.h"
|
#include "postgres_fe.h"
|
||||||
|
|
||||||
#include "dumputils.h"
|
#include "pg_backup_utils.h"
|
||||||
#include "parallel.h"
|
#include "parallel.h"
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
@ -78,10 +78,6 @@ static const char *modulename = gettext_noop("parallel archiver");
|
|||||||
|
|
||||||
static ParallelSlot *GetMyPSlot(ParallelState *pstate);
|
static ParallelSlot *GetMyPSlot(ParallelState *pstate);
|
||||||
static void
|
static void
|
||||||
parallel_exit_msg_func(const char *modulename,
|
|
||||||
const char *fmt, va_list ap)
|
|
||||||
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 0)));
|
|
||||||
static void
|
|
||||||
parallel_msg_master(ParallelSlot *slot, const char *modulename,
|
parallel_msg_master(ParallelSlot *slot, const char *modulename,
|
||||||
const char *fmt, va_list ap)
|
const char *fmt, va_list ap)
|
||||||
__attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 0)));
|
__attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 0)));
|
||||||
@ -112,6 +108,47 @@ static char *readMessageFromPipe(int fd);
|
|||||||
#define messageEquals(msg, pattern) \
|
#define messageEquals(msg, pattern) \
|
||||||
(strcmp(msg, pattern) == 0)
|
(strcmp(msg, pattern) == 0)
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
static void shutdown_parallel_dump_utils(int code, void *unused);
|
||||||
|
bool parallel_init_done = false;
|
||||||
|
static DWORD tls_index;
|
||||||
|
DWORD mainThreadId;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
static void
|
||||||
|
shutdown_parallel_dump_utils(int code, void *unused)
|
||||||
|
{
|
||||||
|
/* Call the cleanup function only from the main thread */
|
||||||
|
if (mainThreadId == GetCurrentThreadId())
|
||||||
|
WSACleanup();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
init_parallel_dump_utils(void)
|
||||||
|
{
|
||||||
|
#ifdef WIN32
|
||||||
|
if (!parallel_init_done)
|
||||||
|
{
|
||||||
|
WSADATA wsaData;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
tls_index = TlsAlloc();
|
||||||
|
mainThreadId = GetCurrentThreadId();
|
||||||
|
err = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||||
|
if (err != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, _("WSAStartup failed: %d\n"), err);
|
||||||
|
exit_nicely(1);
|
||||||
|
}
|
||||||
|
on_exit_nicely(shutdown_parallel_dump_utils, NULL);
|
||||||
|
parallel_init_done = true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static ParallelSlot *
|
static ParallelSlot *
|
||||||
GetMyPSlot(ParallelState *pstate)
|
GetMyPSlot(ParallelState *pstate)
|
||||||
{
|
{
|
||||||
@ -129,29 +166,44 @@ GetMyPSlot(ParallelState *pstate)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the function that will be called from exit_horribly() to print the
|
* Fail and die, with a message to stderr. Parameters as for write_msg.
|
||||||
* error message. If the worker process does exit_horribly(), we forward its
|
*
|
||||||
|
* This is defined in parallel.c, because in parallel mode, things are more
|
||||||
|
* complicated. If the worker process does exit_horribly(), we forward its
|
||||||
* last words to the master process. The master process then does
|
* last words to the master process. The master process then does
|
||||||
* exit_horribly() with this error message itself and prints it normally.
|
* exit_horribly() with this error message itself and prints it normally.
|
||||||
* After printing the message, exit_horribly() on the master will shut down
|
* After printing the message, exit_horribly() on the master will shut down
|
||||||
* the remaining worker processes.
|
* the remaining worker processes.
|
||||||
*/
|
*/
|
||||||
static void
|
void
|
||||||
parallel_exit_msg_func(const char *modulename, const char *fmt, va_list ap)
|
exit_horribly(const char *modulename, const char *fmt,...)
|
||||||
{
|
{
|
||||||
|
va_list ap;
|
||||||
ParallelState *pstate = shutdown_info.pstate;
|
ParallelState *pstate = shutdown_info.pstate;
|
||||||
ParallelSlot *slot;
|
ParallelSlot *slot;
|
||||||
|
|
||||||
Assert(pstate);
|
va_start(ap, fmt);
|
||||||
|
|
||||||
slot = GetMyPSlot(pstate);
|
if (pstate == NULL)
|
||||||
|
{
|
||||||
if (!slot)
|
/* Not in parallel mode, just write to stderr */
|
||||||
/* We're the parent, just write the message out */
|
|
||||||
vwrite_msg(modulename, fmt, ap);
|
vwrite_msg(modulename, fmt, ap);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
/* If we're a worker process, send the msg to the master process */
|
{
|
||||||
parallel_msg_master(slot, modulename, fmt, ap);
|
slot = GetMyPSlot(pstate);
|
||||||
|
|
||||||
|
if (!slot)
|
||||||
|
/* We're the parent, just write the message out */
|
||||||
|
vwrite_msg(modulename, fmt, ap);
|
||||||
|
else
|
||||||
|
/* If we're a worker process, send the msg to the master process */
|
||||||
|
parallel_msg_master(slot, modulename, fmt, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
exit_nicely(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sends the error message from the worker to the master process */
|
/* Sends the error message from the worker to the master process */
|
||||||
@ -172,6 +224,54 @@ parallel_msg_master(ParallelSlot *slot, const char *modulename,
|
|||||||
sendMessageToMaster(pipefd, buf);
|
sendMessageToMaster(pipefd, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A thread-local version of getLocalPQExpBuffer().
|
||||||
|
*
|
||||||
|
* Non-reentrant but reduces memory leakage. (On Windows the memory leakage
|
||||||
|
* will be one buffer per thread, which is at least better than one per call).
|
||||||
|
*/
|
||||||
|
static PQExpBuffer
|
||||||
|
getThreadLocalPQExpBuffer(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The Tls code goes awry if we use a static var, so we provide for both
|
||||||
|
* static and auto, and omit any use of the static var when using Tls.
|
||||||
|
*/
|
||||||
|
static PQExpBuffer s_id_return = NULL;
|
||||||
|
PQExpBuffer id_return;
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
if (parallel_init_done)
|
||||||
|
id_return = (PQExpBuffer) TlsGetValue(tls_index); /* 0 when not set */
|
||||||
|
else
|
||||||
|
id_return = s_id_return;
|
||||||
|
#else
|
||||||
|
id_return = s_id_return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (id_return) /* first time through? */
|
||||||
|
{
|
||||||
|
/* same buffer, just wipe contents */
|
||||||
|
resetPQExpBuffer(id_return);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* new buffer */
|
||||||
|
id_return = createPQExpBuffer();
|
||||||
|
#ifdef WIN32
|
||||||
|
if (parallel_init_done)
|
||||||
|
TlsSetValue(tls_index, id_return);
|
||||||
|
else
|
||||||
|
s_id_return = id_return;
|
||||||
|
#else
|
||||||
|
s_id_return = id_return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return id_return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* pg_dump and pg_restore register the Archive pointer for the exit handler
|
* pg_dump and pg_restore register the Archive pointer for the exit handler
|
||||||
* (called from exit_horribly). This function mainly exists so that we can
|
* (called from exit_horribly). This function mainly exists so that we can
|
||||||
@ -408,7 +508,7 @@ ParallelBackupStart(ArchiveHandle *AH, RestoreOptions *ropt)
|
|||||||
* set and falls back to AHX otherwise.
|
* set and falls back to AHX otherwise.
|
||||||
*/
|
*/
|
||||||
shutdown_info.pstate = pstate;
|
shutdown_info.pstate = pstate;
|
||||||
on_exit_msg_func = parallel_exit_msg_func;
|
getLocalPQExpBuffer = getThreadLocalPQExpBuffer;
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
tMasterThreadId = GetCurrentThreadId();
|
tMasterThreadId = GetCurrentThreadId();
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef PG_DUMP_PARALLEL_H
|
||||||
|
#define PG_DUMP_PARALLEL_H
|
||||||
|
|
||||||
#include "pg_backup_db.h"
|
#include "pg_backup_db.h"
|
||||||
|
|
||||||
struct _archiveHandle;
|
struct _archiveHandle;
|
||||||
@ -62,6 +65,13 @@ typedef struct ParallelState
|
|||||||
ParallelSlot *parallelSlot;
|
ParallelSlot *parallelSlot;
|
||||||
} ParallelState;
|
} 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 int GetIdleWorker(ParallelState *pstate);
|
||||||
extern bool IsEveryWorkerIdle(ParallelState *pstate);
|
extern bool IsEveryWorkerIdle(ParallelState *pstate);
|
||||||
extern void ListenToWorkers(struct _archiveHandle * AH, ParallelState *pstate, bool do_wait);
|
extern void ListenToWorkers(struct _archiveHandle * AH, ParallelState *pstate, bool do_wait);
|
||||||
@ -77,3 +87,9 @@ extern void DispatchJobForTocEntry(struct _archiveHandle * AH,
|
|||||||
extern void ParallelBackupEnd(struct _archiveHandle * AH, ParallelState *pstate);
|
extern void ParallelBackupEnd(struct _archiveHandle * AH, ParallelState *pstate);
|
||||||
|
|
||||||
extern void checkAborting(struct _archiveHandle * AH);
|
extern void checkAborting(struct _archiveHandle * AH);
|
||||||
|
|
||||||
|
extern void
|
||||||
|
exit_horribly(const char *modulename, const char *fmt,...)
|
||||||
|
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3), noreturn));
|
||||||
|
|
||||||
|
#endif /* PG_DUMP_PARALLEL_H */
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "pg_backup_db.h"
|
#include "pg_backup_db.h"
|
||||||
#include "dumputils.h"
|
#include "pg_backup_utils.h"
|
||||||
#include "parallel.h"
|
#include "parallel.h"
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
@ -25,8 +25,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "compress_io.h"
|
#include "compress_io.h"
|
||||||
#include "dumputils.h"
|
|
||||||
#include "parallel.h"
|
#include "parallel.h"
|
||||||
|
#include "pg_backup_utils.h"
|
||||||
|
|
||||||
/*--------
|
/*--------
|
||||||
* Routines in the format interface
|
* Routines in the format interface
|
||||||
|
@ -11,7 +11,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "pg_backup_db.h"
|
#include "pg_backup_db.h"
|
||||||
|
#include "pg_backup_utils.h"
|
||||||
#include "dumputils.h"
|
#include "dumputils.h"
|
||||||
|
#include "parallel.h"
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "compress_io.h"
|
#include "compress_io.h"
|
||||||
#include "dumputils.h"
|
#include "pg_backup_utils.h"
|
||||||
#include "parallel.h"
|
#include "parallel.h"
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
@ -23,7 +23,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "pg_backup_archiver.h"
|
#include "pg_backup_archiver.h"
|
||||||
#include "dumputils.h"
|
#include "pg_backup_utils.h"
|
||||||
|
#include "parallel.h"
|
||||||
|
|
||||||
#include <unistd.h> /* for dup */
|
#include <unistd.h> /* for dup */
|
||||||
|
|
||||||
|
@ -31,7 +31,8 @@
|
|||||||
#include "pg_backup.h"
|
#include "pg_backup.h"
|
||||||
#include "pg_backup_archiver.h"
|
#include "pg_backup_archiver.h"
|
||||||
#include "pg_backup_tar.h"
|
#include "pg_backup_tar.h"
|
||||||
#include "dumputils.h"
|
#include "pg_backup_utils.h"
|
||||||
|
#include "parallel.h"
|
||||||
#include "pgtar.h"
|
#include "pgtar.h"
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
126
src/bin/pg_dump/pg_backup_utils.c
Normal file
126
src/bin/pg_dump/pg_backup_utils.c
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* pg_backup_utils.c
|
||||||
|
* Utility routines shared by pg_dump and pg_restore
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
|
||||||
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
|
*
|
||||||
|
* src/bin/pg_dump/pg_backup_utils.c
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#include "postgres_fe.h"
|
||||||
|
|
||||||
|
#include "pg_backup_utils.h"
|
||||||
|
#include "parallel.h"
|
||||||
|
|
||||||
|
/* Globals exported by this file */
|
||||||
|
const char *progname = NULL;
|
||||||
|
|
||||||
|
#define MAX_ON_EXIT_NICELY 20
|
||||||
|
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
on_exit_nicely_callback function;
|
||||||
|
void *arg;
|
||||||
|
} on_exit_nicely_list[MAX_ON_EXIT_NICELY];
|
||||||
|
|
||||||
|
static int on_exit_nicely_index;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse a --section=foo command line argument.
|
||||||
|
*
|
||||||
|
* Set or update the bitmask in *dumpSections according to arg.
|
||||||
|
* dumpSections is initialised as DUMP_UNSECTIONED by pg_dump and
|
||||||
|
* pg_restore so they can know if this has even been called.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
set_dump_section(const char *arg, int *dumpSections)
|
||||||
|
{
|
||||||
|
/* if this is the first call, clear all the bits */
|
||||||
|
if (*dumpSections == DUMP_UNSECTIONED)
|
||||||
|
*dumpSections = 0;
|
||||||
|
|
||||||
|
if (strcmp(arg, "pre-data") == 0)
|
||||||
|
*dumpSections |= DUMP_PRE_DATA;
|
||||||
|
else if (strcmp(arg, "data") == 0)
|
||||||
|
*dumpSections |= DUMP_DATA;
|
||||||
|
else if (strcmp(arg, "post-data") == 0)
|
||||||
|
*dumpSections |= DUMP_POST_DATA;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, _("%s: unrecognized section name: \"%s\"\n"),
|
||||||
|
progname, arg);
|
||||||
|
fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
|
||||||
|
progname);
|
||||||
|
exit_nicely(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write a printf-style message to stderr.
|
||||||
|
*
|
||||||
|
* The program name is prepended, if "progname" has been set.
|
||||||
|
* Also, if modulename isn't NULL, that's included too.
|
||||||
|
* Note that we'll try to translate the modulename and the fmt string.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
write_msg(const char *modulename, const char *fmt,...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vwrite_msg(modulename, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* As write_msg, but pass a va_list not variable arguments.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
vwrite_msg(const char *modulename, const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
if (progname)
|
||||||
|
{
|
||||||
|
if (modulename)
|
||||||
|
fprintf(stderr, "%s: [%s] ", progname, _(modulename));
|
||||||
|
else
|
||||||
|
fprintf(stderr, "%s: ", progname);
|
||||||
|
}
|
||||||
|
vfprintf(stderr, _(fmt), ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register a callback to be run when exit_nicely is invoked. */
|
||||||
|
void
|
||||||
|
on_exit_nicely(on_exit_nicely_callback function, void *arg)
|
||||||
|
{
|
||||||
|
if (on_exit_nicely_index >= MAX_ON_EXIT_NICELY)
|
||||||
|
exit_horribly(NULL, "out of on_exit_nicely slots\n");
|
||||||
|
on_exit_nicely_list[on_exit_nicely_index].function = function;
|
||||||
|
on_exit_nicely_list[on_exit_nicely_index].arg = arg;
|
||||||
|
on_exit_nicely_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Run accumulated on_exit_nicely callbacks in reverse order and then exit
|
||||||
|
* quietly. This needs to be thread-safe.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
exit_nicely(int code)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = on_exit_nicely_index - 1; i >= 0; i--)
|
||||||
|
(*on_exit_nicely_list[i].function) (code,
|
||||||
|
on_exit_nicely_list[i].arg);
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
if (parallel_init_done && GetCurrentThreadId() != mainThreadId)
|
||||||
|
ExitThread(code);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
exit(code);
|
||||||
|
}
|
40
src/bin/pg_dump/pg_backup_utils.h
Normal file
40
src/bin/pg_dump/pg_backup_utils.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* pg_backup_utils.h
|
||||||
|
* Utility routines shared by pg_dump and pg_restore.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
|
||||||
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
|
*
|
||||||
|
* src/bin/pg_dump/pg_backup_utils.h
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PG_BACKUP_UTILS_H
|
||||||
|
#define PG_BACKUP_UTILS_H
|
||||||
|
|
||||||
|
typedef enum /* bits returned by set_dump_section */
|
||||||
|
{
|
||||||
|
DUMP_PRE_DATA = 0x01,
|
||||||
|
DUMP_DATA = 0x02,
|
||||||
|
DUMP_POST_DATA = 0x04,
|
||||||
|
DUMP_UNSECTIONED = 0xff
|
||||||
|
} DumpSections;
|
||||||
|
|
||||||
|
typedef void (*on_exit_nicely_callback) (int code, void *arg);
|
||||||
|
|
||||||
|
extern const char *progname;
|
||||||
|
|
||||||
|
extern void set_dump_section(const char *arg, int *dumpSections);
|
||||||
|
extern void
|
||||||
|
write_msg(const char *modulename, const char *fmt,...)
|
||||||
|
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
|
||||||
|
extern void
|
||||||
|
vwrite_msg(const char *modulename, const char *fmt, va_list ap)
|
||||||
|
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 0)));
|
||||||
|
extern void on_exit_nicely(on_exit_nicely_callback function, void *arg);
|
||||||
|
extern void exit_nicely(int code) __attribute__((noreturn));
|
||||||
|
|
||||||
|
#endif /* PG_BACKUP_UTILS_H */
|
@ -59,7 +59,9 @@
|
|||||||
|
|
||||||
#include "pg_backup_archiver.h"
|
#include "pg_backup_archiver.h"
|
||||||
#include "pg_backup_db.h"
|
#include "pg_backup_db.h"
|
||||||
|
#include "pg_backup_utils.h"
|
||||||
#include "dumputils.h"
|
#include "dumputils.h"
|
||||||
|
#include "parallel.h"
|
||||||
|
|
||||||
extern char *optarg;
|
extern char *optarg;
|
||||||
extern int optind,
|
extern int optind,
|
||||||
|
@ -14,7 +14,8 @@
|
|||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#include "pg_backup_archiver.h"
|
#include "pg_backup_archiver.h"
|
||||||
#include "dumputils.h"
|
#include "pg_backup_utils.h"
|
||||||
|
#include "parallel.h"
|
||||||
|
|
||||||
/* translator: this is a module name */
|
/* translator: this is a module name */
|
||||||
static const char *modulename = gettext_noop("sorter");
|
static const char *modulename = gettext_noop("sorter");
|
||||||
|
@ -63,6 +63,7 @@ static PGresult *executeQuery(PGconn *conn, const char *query);
|
|||||||
static void executeCommand(PGconn *conn, const char *query);
|
static void executeCommand(PGconn *conn, const char *query);
|
||||||
|
|
||||||
static char pg_dump_bin[MAXPGPATH];
|
static char pg_dump_bin[MAXPGPATH];
|
||||||
|
static const char *progname;
|
||||||
static PQExpBuffer pgdumpopts;
|
static PQExpBuffer pgdumpopts;
|
||||||
static char *connstr = "";
|
static char *connstr = "";
|
||||||
static bool skip_acls = false;
|
static bool skip_acls = false;
|
||||||
@ -82,6 +83,7 @@ static int server_version;
|
|||||||
static FILE *OPF;
|
static FILE *OPF;
|
||||||
static char *filename = NULL;
|
static char *filename = NULL;
|
||||||
|
|
||||||
|
#define exit_nicely(code) exit(code)
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
|
@ -40,8 +40,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "pg_backup_archiver.h"
|
#include "pg_backup_archiver.h"
|
||||||
|
#include "pg_backup_utils.h"
|
||||||
#include "dumputils.h"
|
#include "dumputils.h"
|
||||||
|
#include "parallel.h"
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user