aboutsummaryrefslogtreecommitdiff
path: root/src/bin/pg_dump/parallel.c
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2013-03-27 18:10:40 +0200
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2013-03-27 18:10:40 +0200
commit7800a71291690dcc34eb3b7aab18750b5a7ebe2c (patch)
treece2832159c7f6486c12faff5191b114339ee8065 /src/bin/pg_dump/parallel.c
parent1cea9bbb21e9e90dc7085ce605d9160e7161fa58 (diff)
downloadpostgresql-7800a71291690dcc34eb3b7aab18750b5a7ebe2c.tar.gz
postgresql-7800a71291690dcc34eb3b7aab18750b5a7ebe2c.zip
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.
Diffstat (limited to 'src/bin/pg_dump/parallel.c')
-rw-r--r--src/bin/pg_dump/parallel.c136
1 files changed, 118 insertions, 18 deletions
diff --git a/src/bin/pg_dump/parallel.c b/src/bin/pg_dump/parallel.c
index dedf4311b9e..ae0d329ea21 100644
--- a/src/bin/pg_dump/parallel.c
+++ b/src/bin/pg_dump/parallel.c
@@ -16,9 +16,9 @@
*-------------------------------------------------------------------------
*/
-#include "pg_backup_db.h"
+#include "postgres_fe.h"
-#include "dumputils.h"
+#include "pg_backup_utils.h"
#include "parallel.h"
#ifndef WIN32
@@ -78,10 +78,6 @@ 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)));
@@ -112,6 +108,47 @@ static char *readMessageFromPipe(int fd);
#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
+
+
+#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 *
GetMyPSlot(ParallelState *pstate)
{
@@ -129,29 +166,44 @@ GetMyPSlot(ParallelState *pstate)
}
/*
- * 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
+ * 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.
*/
-static void
-parallel_exit_msg_func(const char *modulename, const char *fmt, va_list ap)
+void
+exit_horribly(const char *modulename, const char *fmt,...)
{
+ va_list ap;
ParallelState *pstate = shutdown_info.pstate;
ParallelSlot *slot;
- Assert(pstate);
+ va_start(ap, fmt);
- slot = GetMyPSlot(pstate);
-
- if (!slot)
- /* We're the parent, just write the message out */
+ if (pstate == NULL)
+ {
+ /* Not in parallel mode, just write to stderr */
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);
+ {
+ 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 */
@@ -173,6 +225,54 @@ parallel_msg_master(ParallelSlot *slot, const char *modulename,
}
/*
+ * 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
* keep shutdown_info in file scope only.
@@ -408,7 +508,7 @@ ParallelBackupStart(ArchiveHandle *AH, RestoreOptions *ropt)
* set and falls back to AHX otherwise.
*/
shutdown_info.pstate = pstate;
- on_exit_msg_func = parallel_exit_msg_func;
+ getLocalPQExpBuffer = getThreadLocalPQExpBuffer;
#ifdef WIN32
tMasterThreadId = GetCurrentThreadId();