On 26.03.2013 09:51, Heikki Linnakangas wrote:
On 26.03.2013 02:02, Tom Lane wrote:
Heikki Linnakangas<[email protected]> writes:
On 25.03.2013 15:36, Tom Lane wrote:
Heikki Linnakangas<[email protected]> writes:
Add PF_PRINTF_ATTRIBUTE to on_exit_msg_fmt.
Per warning from -Wmissing-format-attribute.

Hm, this is exactly what I removed yesterday, because it makes the
build
fail outright on old gcc:

The attached seems to work. With this patch, on_exit_msg_func() is gone.
There's a different implementation of exit_horribly for pg_dumpall and
pg_dump/restore. In pg_dumpall, it just calls vwrite_msg(). In
pg_dump/restore's version, the logic from parallel_exit_msg_func() is
moved directly to exit_horribly().

Seems probably reasonable, though if we're taking exit_horribly out of
dumputils.c, meseems it ought not be declared in dumputils.h anymore.
Can we put that declaration someplace else, rather than commenting it
with an apology?

Ugh, the patch I posted doesn't actually work, because dumputils.c is
also used in psql and some scripts, so you get a linker error in those.
psql and scripts don't use exit_horribly or many of the other functions
in dumputils.c, so I think we should split dumputils.c into two parts
anyway. fmtId and the other functions that are used by psql in one file,
and the functions that are only shared between pg_dumpall and pg_dump in
another. Then there's also functions that are used by pg_dump and
pg_restore, but not pg_dumpall or psql.

I'll try moving things around a bit...

This is what I came up with. I created a new file, misc.c (for lack of a better name), for things that are shared by pg_dump and pg_restore, but not pg_dumpall or other programs. I moved all the parallel stuff from dumputils.c to parallel.c, and everything else that's not used outside pg_dump and pg_restore to misc.c. I moved exit_horribly() to parallel.c, because it needs to do things differently in parallel mode.

I still used a function pointer, not for the printf-style message printing routine, but for making dumputils.c independent of parallel mode. getThreadLocalPQBuffer() is now a function pointer; the default implementation just uses a static variable, but when pg_dump/restore enters parallel mode, it points the function pointer to a version that uses thread-local storage (on windows).

- Heikki
*** a/src/bin/pg_dump/Makefile
--- b/src/bin/pg_dump/Makefile
***************
*** 19,25 **** include $(top_builddir)/src/Makefile.global
  override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS)
  
  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_directory.o dumputils.o compress_io.o $(WIN32RES)
  
  KEYWRDOBJS = keywords.o kwlookup.o
--- 19,25 ----
  override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS)
  
  OBJS=	pg_backup_archiver.o pg_backup_db.o pg_backup_custom.o \
! 	pg_backup_null.o pg_backup_tar.o parallel.o misc.o \
  	pg_backup_directory.o dumputils.o compress_io.o $(WIN32RES)
  
  KEYWRDOBJS = keywords.o kwlookup.o
*** a/src/bin/pg_dump/common.c
--- b/src/bin/pg_dump/common.c
***************
*** 14,19 ****
--- 14,20 ----
   *-------------------------------------------------------------------------
   */
  #include "pg_backup_archiver.h"
+ #include "misc.h"
  
  #include <ctype.h>
  
*** a/src/bin/pg_dump/compress_io.c
--- b/src/bin/pg_dump/compress_io.c
***************
*** 53,59 ****
   */
  
  #include "compress_io.h"
! #include "dumputils.h"
  #include "parallel.h"
  
  /*----------------------
--- 53,59 ----
   */
  
  #include "compress_io.h"
! #include "misc.h"
  #include "parallel.h"
  
  /*----------------------
*** a/src/bin/pg_dump/dumputils.c
--- b/src/bin/pg_dump/dumputils.c
***************
*** 25,45 ****
  extern const ScanKeyword FEScanKeywords[];
  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)
  
  static bool parseAclItem(const char *item, const char *type,
--- 25,30 ----
***************
*** 49,116 **** static bool parseAclItem(const char *item, const char *type,
  static char *copyAclUserName(PQExpBuffer output, char *input);
  static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
  	   const char *subname);
! static PQExpBuffer getThreadLocalPQExpBuffer(void);
! 
! #ifdef WIN32
! static void shutdown_parallel_dump_utils(int code, void *unused);
! static bool parallel_init_done = false;
! 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
!  * 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? */
  	{
--- 34,57 ----
  static char *copyAclUserName(PQExpBuffer output, char *input);
  static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
  	   const char *subname);
! static PQExpBuffer defaultGetLocalPQExpBuffer(void);
  
! /* Globals exported by this file */
! int			quote_all_identifiers = 0;
! PQExpBuffer (*getLocalPQExpBuffer) (void) = defaultGetLocalPQExpBuffer;
  
  /*
!  * Returns a temporary PQExpBuffer, valid until the next call to the function.
!  * 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
! defaultGetLocalPQExpBuffer(void)
  {
! 	static PQExpBuffer id_return = NULL;
  
  	if (id_return)				/* first time through? */
  	{
***************
*** 121,135 **** getThreadLocalPQExpBuffer(void)
  	{
  		/* 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;
--- 62,67 ----
***************
*** 144,150 **** getThreadLocalPQExpBuffer(void)
  const char *
  fmtId(const char *rawid)
  {
! 	PQExpBuffer id_return = getThreadLocalPQExpBuffer();
  
  	const char *cp;
  	bool		need_quotes = false;
--- 76,82 ----
  const char *
  fmtId(const char *rawid)
  {
! 	PQExpBuffer id_return = getLocalPQExpBuffer();
  
  	const char *cp;
  	bool		need_quotes = false;
***************
*** 238,244 **** fmtQualifiedId(int remoteVersion, const char *schema, const char *id)
  	}
  	appendPQExpBuffer(lcl_pqexp, "%s", fmtId(id));
  
! 	id_return = getThreadLocalPQExpBuffer();
  
  	appendPQExpBuffer(id_return, "%s", lcl_pqexp->data);
  	destroyPQExpBuffer(lcl_pqexp);
--- 170,176 ----
  	}
  	appendPQExpBuffer(lcl_pqexp, "%s", fmtId(id));
  
! 	id_return = getLocalPQExpBuffer();
  
  	appendPQExpBuffer(id_return, "%s", lcl_pqexp->data);
  	destroyPQExpBuffer(lcl_pqexp);
***************
*** 1278,1395 **** 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
  simple_string_list_append(SimpleStringList *list, const char *val)
  {
--- 1210,1215 ----
*** a/src/bin/pg_dump/dumputils.h
--- b/src/bin/pg_dump/dumputils.h
***************
*** 19,32 ****
  #include "libpq-fe.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
  {
  	struct SimpleStringListCell *next;
--- 19,24 ----
***************
*** 40,53 **** typedef struct SimpleStringList
  } SimpleStringList;
  
  
- typedef void (*on_exit_nicely_callback) (int code, void *arg);
- 
  extern int	quote_all_identifiers;
! extern const char *progname;
! 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 *fmtQualifiedId(int remoteVersion,
  			   const char *schema, const char *id);
--- 32,40 ----
  } SimpleStringList;
  
  
  extern int	quote_all_identifiers;
! extern PQExpBuffer (*getLocalPQExpBuffer) (void);
  
  extern const char *fmtId(const char *identifier);
  extern const char *fmtQualifiedId(int remoteVersion,
  			   const char *schema, const char *id);
***************
*** 79,95 **** extern void buildShSecLabelQuery(PGconn *conn, const char *catalog_name,
  extern void emitShSecLabels(PGconn *conn, PGresult *res,
  				PQExpBuffer buffer, const char *target, const char *objname);
  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 bool simple_string_list_member(SimpleStringList *list, const char *val);
--- 66,71 ----
*** /dev/null
--- b/src/bin/pg_dump/misc.c
***************
*** 0 ****
--- 1,126 ----
+ /*-------------------------------------------------------------------------
+  *
+  * misc.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/misc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres_fe.h"
+ 
+ #include "misc.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);
+ }
*** /dev/null
--- b/src/bin/pg_dump/misc.h
***************
*** 0 ****
--- 1,47 ----
+ /*-------------------------------------------------------------------------
+  *
+  * misc.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/misc.h
+  *
+  *-------------------------------------------------------------------------
+  */
+ 
+ #ifndef PG_DUMP_MISC_H
+ #define PG_DUMP_MISC_H
+ 
+ #include "libpq-fe.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 void (*on_exit_nicely_callback) (int code, void *arg);
+ 
+ extern const char *progname;
+ extern void (*on_exit_msg_func) (const char *modulename, const char *fmt, va_list ap)
+ __attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 0)));
+ 
+ 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));
+ 
+ extern void init_parallel_dump_utils(void);
+ 
+ #endif   /* PG_DUMP_MISC_H */
*** a/src/bin/pg_dump/parallel.c
--- b/src/bin/pg_dump/parallel.c
***************
*** 16,24 ****
   *-------------------------------------------------------------------------
   */
  
! #include "pg_backup_db.h"
  
! #include "dumputils.h"
  #include "parallel.h"
  
  #ifndef WIN32
--- 16,24 ----
   *-------------------------------------------------------------------------
   */
  
! #include "postgres_fe.h"
  
! #include "misc.h"
  #include "parallel.h"
  
  #ifndef WIN32
***************
*** 78,87 **** static const char *modulename = gettext_noop("parallel archiver");
  
  static ParallelSlot *GetMyPSlot(ParallelState *pstate);
  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,
  					const char *fmt, va_list ap)
  __attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 0)));
--- 78,83 ----
***************
*** 112,117 **** static char *readMessageFromPipe(int fd);
--- 108,120 ----
  #define messageEquals(msg, pattern) \
  	(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
+ 
  static ParallelSlot *
  GetMyPSlot(ParallelState *pstate)
  {
***************
*** 128,157 **** GetMyPSlot(ParallelState *pstate)
  	return NULL;
  }
  
  /*
!  * This is the function that will be called from exit_horribly() to print the
!  * error message. If the worker process does exit_horribly(), we forward its
   * last words to the master process. The master process then does
   * exit_horribly() with this error message itself and prints it normally.
   * After printing the message, exit_horribly() on the master will shut down
   * the remaining worker processes.
   */
! static void
! parallel_exit_msg_func(const char *modulename, const char *fmt, va_list ap)
  {
  	ParallelState *pstate = shutdown_info.pstate;
  	ParallelSlot *slot;
  
! 	Assert(pstate);
  
! 	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);
  }
  
  /* Sends the error message from the worker to the master process */
--- 131,176 ----
  	return NULL;
  }
  
+ 
  /*
!  * Fail and die, with a message to stderr.	Parameters as for write_msg.
!  *
!  * 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
   * exit_horribly() with this error message itself and prints it normally.
   * After printing the message, exit_horribly() on the master will shut down
   * the remaining worker processes.
   */
! void
! exit_horribly(const char *modulename, const char *fmt,...)
  {
+ 	va_list		ap;
  	ParallelState *pstate = shutdown_info.pstate;
  	ParallelSlot *slot;
  
! 	va_start(ap, fmt);
  
! 	if (pstate == NULL)
! 	{
! 		/* Not in parallel mode, just write to stderr */
  		vwrite_msg(modulename, fmt, ap);
+ 	}
  	else
! 	{
! 		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 */
***************
*** 172,177 **** parallel_msg_master(ParallelSlot *slot, const char *modulename,
--- 191,277 ----
  	sendMessageToMaster(pipefd, buf);
  }
  
+ #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
+ }
+ 
+ /*
+  * 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
   * (called from exit_horribly). This function mainly exists so that we can
***************
*** 408,414 **** ParallelBackupStart(ArchiveHandle *AH, RestoreOptions *ropt)
  	 * set and falls back to AHX otherwise.
  	 */
  	shutdown_info.pstate = pstate;
! 	on_exit_msg_func = parallel_exit_msg_func;
  
  #ifdef WIN32
  	tMasterThreadId = GetCurrentThreadId();
--- 508,514 ----
  	 * set and falls back to AHX otherwise.
  	 */
  	shutdown_info.pstate = pstate;
! 	getLocalPQExpBuffer = getThreadLocalPQExpBuffer;
  
  #ifdef WIN32
  	tMasterThreadId = GetCurrentThreadId();
*** a/src/bin/pg_dump/parallel.h
--- b/src/bin/pg_dump/parallel.h
***************
*** 16,21 ****
--- 16,24 ----
   *-------------------------------------------------------------------------
   */
  
+ #ifndef PG_DUMP_PARALLEL_H
+ #define PG_DUMP_PARALLEL_H
+ 
  #include "pg_backup_db.h"
  
  struct _archiveHandle;
***************
*** 62,67 **** typedef struct ParallelState
--- 65,75 ----
  	ParallelSlot *parallelSlot;
  } ParallelState;
  
+ #ifdef WIN32
+ extern bool parallel_init_done;
+ extern DWORD mainThreadId;
+ #endif
+ 
  extern int	GetIdleWorker(ParallelState *pstate);
  extern bool IsEveryWorkerIdle(ParallelState *pstate);
  extern void ListenToWorkers(struct _archiveHandle * AH, ParallelState *pstate, bool do_wait);
***************
*** 77,79 **** extern void DispatchJobForTocEntry(struct _archiveHandle * AH,
--- 85,93 ----
  extern void ParallelBackupEnd(struct _archiveHandle * AH, ParallelState *pstate);
  
  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 */
*** a/src/bin/pg_dump/pg_backup_archiver.c
--- b/src/bin/pg_dump/pg_backup_archiver.c
***************
*** 21,27 ****
   */
  
  #include "pg_backup_db.h"
! #include "dumputils.h"
  #include "parallel.h"
  
  #include <ctype.h>
--- 21,27 ----
   */
  
  #include "pg_backup_db.h"
! #include "misc.h"
  #include "parallel.h"
  
  #include <ctype.h>
*** a/src/bin/pg_dump/pg_backup_custom.c
--- b/src/bin/pg_dump/pg_backup_custom.c
***************
*** 25,31 ****
   */
  
  #include "compress_io.h"
! #include "dumputils.h"
  #include "parallel.h"
  
  /*--------
--- 25,31 ----
   */
  
  #include "compress_io.h"
! #include "misc.h"
  #include "parallel.h"
  
  /*--------
*** a/src/bin/pg_dump/pg_backup_db.c
--- b/src/bin/pg_dump/pg_backup_db.c
***************
*** 12,17 ****
--- 12,19 ----
  
  #include "pg_backup_db.h"
  #include "dumputils.h"
+ #include "misc.h"
+ #include "parallel.h"
  
  #include <unistd.h>
  #include <ctype.h>
*** a/src/bin/pg_dump/pg_backup_directory.c
--- b/src/bin/pg_dump/pg_backup_directory.c
***************
*** 34,40 ****
   */
  
  #include "compress_io.h"
! #include "dumputils.h"
  #include "parallel.h"
  
  #include <dirent.h>
--- 34,40 ----
   */
  
  #include "compress_io.h"
! #include "misc.h"
  #include "parallel.h"
  
  #include <dirent.h>
*** a/src/bin/pg_dump/pg_backup_null.c
--- b/src/bin/pg_dump/pg_backup_null.c
***************
*** 23,29 ****
   */
  
  #include "pg_backup_archiver.h"
! #include "dumputils.h"
  
  #include <unistd.h>				/* for dup */
  
--- 23,30 ----
   */
  
  #include "pg_backup_archiver.h"
! #include "misc.h"
! #include "parallel.h"
  
  #include <unistd.h>				/* for dup */
  
*** a/src/bin/pg_dump/pg_backup_tar.c
--- b/src/bin/pg_dump/pg_backup_tar.c
***************
*** 31,37 ****
  #include "pg_backup.h"
  #include "pg_backup_archiver.h"
  #include "pg_backup_tar.h"
! #include "dumputils.h"
  #include "pgtar.h"
  
  #include <sys/stat.h>
--- 31,38 ----
  #include "pg_backup.h"
  #include "pg_backup_archiver.h"
  #include "pg_backup_tar.h"
! #include "misc.h"
! #include "parallel.h"
  #include "pgtar.h"
  
  #include <sys/stat.h>
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
***************
*** 60,65 ****
--- 60,67 ----
  #include "pg_backup_archiver.h"
  #include "pg_backup_db.h"
  #include "dumputils.h"
+ #include "misc.h"
+ #include "parallel.h"
  
  extern char *optarg;
  extern int	optind,
*** a/src/bin/pg_dump/pg_dump_sort.c
--- b/src/bin/pg_dump/pg_dump_sort.c
***************
*** 14,20 ****
   *-------------------------------------------------------------------------
   */
  #include "pg_backup_archiver.h"
! #include "dumputils.h"
  
  /* translator: this is a module name */
  static const char *modulename = gettext_noop("sorter");
--- 14,21 ----
   *-------------------------------------------------------------------------
   */
  #include "pg_backup_archiver.h"
! #include "misc.h"
! #include "parallel.h"
  
  /* translator: this is a module name */
  static const char *modulename = gettext_noop("sorter");
*** a/src/bin/pg_dump/pg_dumpall.c
--- b/src/bin/pg_dump/pg_dumpall.c
***************
*** 63,68 **** static PGresult *executeQuery(PGconn *conn, const char *query);
--- 63,69 ----
  static void executeCommand(PGconn *conn, const char *query);
  
  static char pg_dump_bin[MAXPGPATH];
+ static const char *progname;
  static PQExpBuffer pgdumpopts;
  static char *connstr = "";
  static bool skip_acls = false;
***************
*** 82,87 **** static int	server_version;
--- 83,89 ----
  static FILE *OPF;
  static char *filename = NULL;
  
+ #define exit_nicely(code) exit(code)
  
  int
  main(int argc, char *argv[])
*** a/src/bin/pg_dump/pg_restore.c
--- b/src/bin/pg_dump/pg_restore.c
***************
*** 42,47 ****
--- 42,48 ----
  #include "pg_backup_archiver.h"
  
  #include "dumputils.h"
+ #include "misc.h"
  
  #include <ctype.h>
  
-- 
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to