diff --git a/src/bin/scripts/vac_parallel.c b/src/bin/scripts/vac_parallel.c
new file mode 100644
index 0000000..da56f86
--- /dev/null
+++ b/src/bin/scripts/vac_parallel.c
@@ -0,0 +1,1007 @@
+/*-------------------------------------------------------------------------
+ *
+ * vac_parallel.c
+ *
+ *	Parallel support for the vacuumdb
+ *
+ * Portions Copyright (c) 1996-2013, 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/scripts/vac_parallel.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres_fe.h"
+#include "vac_parallel.h"
+
+#ifndef WIN32
+#include <sys/types.h>
+#include <sys/wait.h>
+#include "signal.h"
+#include <unistd.h>
+#include <fcntl.h>
+#endif
+
+#include "common.h"
+
+#define PIPE_READ							0
+#define PIPE_WRITE							1
+
+/* file-scope variables */
+#ifdef WIN32
+static unsigned int tMasterThreadId = 0;
+static HANDLE termEvent = INVALID_HANDLE_VALUE;
+static int	pgpipe(int handles[2]);
+static int	piperead(int s, char *buf, int len);
+bool		parallel_init_done = false;
+DWORD		mainThreadId;
+
+/*
+ * Structure to hold info passed by _beginthreadex() to the function it calls
+ * via its single allowed argument.
+ */
+typedef struct
+{
+	VacuumOption *vopt;
+	int			worker;
+	int			pipeRead;
+	int			pipeWrite;
+} WorkerInfo;
+
+#define pipewrite(a,b,c)	send(a,b,c,0)
+#else
+/*
+ * aborting is only ever used in the master, the workers are fine with just
+ * wantAbort.
+ */
+static bool aborting = false;
+static volatile sig_atomic_t wantAbort = 0;
+
+#define pgpipe(a)			pipe(a)
+#define piperead(a,b,c)		read(a,b,c)
+#define pipewrite(a,b,c)	write(a,b,c)
+#endif
+
+static const char *modulename = gettext_noop("parallel vacuum");
+
+typedef struct ShutdownInformation
+{
+	ParallelState *pstate;
+	PGconn        *conn;
+} ShutdownInformation;
+
+static ShutdownInformation shutdown_info;
+
+static char *readMessageFromPipe(int fd);
+static void
+SetupWorker(PGconn *connection, int pipefd[2], int worker);
+static void
+WaitForCommands(PGconn * connection, int pipefd[2]);
+static char *
+getMessageFromMaster(int pipefd[2]);
+#define messageStartsWith(msg, prefix) \
+	(strncmp(msg, prefix, strlen(prefix)) == 0)
+#define messageEquals(msg, pattern) \
+	(strcmp(msg, pattern) == 0)
+static char *
+getMessageFromWorker(ParallelState *pstate, bool do_wait, int *worker);
+
+static void
+sendMessageToMaster(int pipefd[2], const char *str);
+
+#ifndef WIN32
+static void sigTermHandler(int signum);
+#endif
+
+static ParallelSlot *
+GetMyPSlot(ParallelState *pstate);
+static int
+select_loop(int maxFd, fd_set *workerset);
+void
+exit_horribly(const char *modulename, const char *fmt,...);
+void
+init_parallel_vacuum_utils(void);
+
+static void  exit_nicely(int code);
+
+static bool
+HasEveryWorkerTerminated(ParallelState *pstate);
+
+static ParallelSlot *
+GetMyPSlot(ParallelState *pstate)
+{
+	int			i;
+
+	for (i = 0; i < pstate->numWorkers; i++)
+#ifdef WIN32
+		if (pstate->parallelSlot[i].threadId == GetCurrentThreadId())
+#else
+		if (pstate->parallelSlot[i].pid == getpid())
+#endif
+			return &(pstate->parallelSlot[i]);
+
+	return NULL;
+}
+
+/* Sends the error message from the worker to the master process */
+static void
+parallel_msg_master(ParallelSlot *slot, const char *modulename,
+					const char *fmt, va_list ap)
+{
+	char		buf[512];
+	int			pipefd[2];
+
+	pipefd[PIPE_READ] = slot->pipeRevRead;
+	pipefd[PIPE_WRITE] = slot->pipeRevWrite;
+
+	strcpy(buf, "ERROR ");
+	vsnprintf(buf + strlen("ERROR "),
+			  sizeof(buf) - strlen("ERROR "), fmt, ap);
+
+	sendMessageToMaster(pipefd, buf);
+}
+
+/*
+ * Wait for the termination of the processes using the OS-specific method.
+ */
+static void
+WaitForTerminatingWorkers(ParallelState *pstate)
+{
+	while (!HasEveryWorkerTerminated(pstate))
+	{
+		ParallelSlot *slot = NULL;
+		int			j;
+
+#ifndef WIN32
+		int			status;
+		pid_t		pid = wait(&status);
+
+		for (j = 0; j < pstate->numWorkers; j++)
+			if (pstate->parallelSlot[j].pid == pid)
+				slot = &(pstate->parallelSlot[j]);
+#else
+		uintptr_t	hThread;
+		DWORD		ret;
+		uintptr_t  *lpHandles = pg_malloc(sizeof(HANDLE) * pstate->numWorkers);
+		int			nrun = 0;
+
+		for (j = 0; j < pstate->numWorkers; j++)
+			if (pstate->parallelSlot[j].workerStatus != WRKR_TERMINATED)
+			{
+				lpHandles[nrun] = pstate->parallelSlot[j].hThread;
+				nrun++;
+			}
+		ret = WaitForMultipleObjects(nrun, (HANDLE *) lpHandles, false, INFINITE);
+		Assert(ret != WAIT_FAILED);
+		hThread = lpHandles[ret - WAIT_OBJECT_0];
+
+		for (j = 0; j < pstate->numWorkers; j++)
+			if (pstate->parallelSlot[j].hThread == hThread)
+				slot = &(pstate->parallelSlot[j]);
+
+		free(lpHandles);
+#endif
+		Assert(slot);
+
+		slot->workerStatus = WRKR_TERMINATED;
+	}
+	Assert(HasEveryWorkerTerminated(pstate));
+}
+
+
+#ifdef WIN32
+static unsigned __stdcall
+init_spawned_worker_win32(WorkerInfo *wi)
+{
+	PGconn *conn;
+	int			pipefd[2] = {wi->pipeRead, wi->pipeWrite};
+	int			worker = wi->worker;
+	VacuumOption *vopt = wi->vopt;
+
+    conn = connectDatabase(vopt->dbname, vopt->pghost, vopt->pgport, vopt->username, 1,
+		vopt->progname, false);
+
+	free(wi);
+	SetupWorker(conn, pipefd, worker);
+	_endthreadex(0);
+	return 0;
+}
+#endif
+
+
+
+ParallelState * ParallelVacuumStart(VacuumOption *vopt, int numWorkers)
+{
+	ParallelState *pstate;
+	int			i;
+	const size_t slotSize = numWorkers * sizeof(ParallelSlot);
+
+	Assert(numWorkers > 0);
+
+	/* Ensure stdio state is quiesced before forking */
+	fflush(NULL);
+
+	pstate = (ParallelState *) pg_malloc(sizeof(ParallelState));
+
+	pstate->numWorkers = numWorkers;
+	pstate->parallelSlot = NULL;
+
+	if (numWorkers == 1)
+		return pstate;
+
+	pstate->parallelSlot = (ParallelSlot *) pg_malloc(slotSize);
+	memset((void *) pstate->parallelSlot, 0, slotSize);
+
+	/*
+	 * Set the pstate in the shutdown_info. The exit handler uses pstate if
+	 * set and falls back to AHX otherwise.
+	 */
+#ifdef WIN32
+	tMasterThreadId = GetCurrentThreadId();
+#endif
+
+	for (i = 0; i < pstate->numWorkers; i++)
+	{
+#ifdef WIN32
+		WorkerInfo *wi;
+		uintptr_t	handle;
+#else
+		pid_t		pid;
+#endif
+		int			pipeMW[2],
+					pipeWM[2];
+
+		if (pgpipe(pipeMW) < 0 || pgpipe(pipeWM) < 0)
+			exit_horribly(modulename,
+						  "could not create communication channels: %s\n",
+						  strerror(errno));
+
+		pstate->parallelSlot[i].workerStatus = WRKR_IDLE;
+		pstate->parallelSlot[i].args = (ParallelArgs *) pg_malloc(sizeof(ParallelArgs));
+#ifdef WIN32
+		/* Allocate a new structure for every worker */
+		wi = (WorkerInfo *) pg_malloc(sizeof(WorkerInfo));
+		wi->worker = i;
+		wi->pipeRead = pstate->parallelSlot[i].pipeRevRead = pipeMW[PIPE_READ];
+		wi->pipeWrite = pstate->parallelSlot[i].pipeRevWrite = pipeWM[PIPE_WRITE];
+        wi->vopt = vopt;
+		handle = _beginthreadex(NULL, 0, (void *) &init_spawned_worker_win32,
+								wi, 0, &(pstate->parallelSlot[i].threadId));
+		pstate->parallelSlot[i].hThread = handle;
+#else
+		pid = fork();
+		if (pid == 0)
+		{
+			/* we are the worker */
+			int			j;
+			int			pipefd[2] = {pipeMW[PIPE_READ], pipeWM[PIPE_WRITE]};
+
+			/*
+			 * Store the fds for the reverse communication in pstate. Actually
+			 * we only use this in case of an error and don't use pstate
+			 * otherwise in the worker process. On Windows we write to the
+			 * global pstate, in Unix we write to our process-local copy but
+			 * that's also where we'd retrieve this information back from.
+			 */
+			pstate->parallelSlot[i].pipeRevRead = pipefd[PIPE_READ];
+			pstate->parallelSlot[i].pipeRevWrite = pipefd[PIPE_WRITE];
+			pstate->parallelSlot[i].pid = getpid();
+
+			pstate->parallelSlot[i].args->connection
+			        = connectDatabase(vopt->dbname, vopt->pghost, vopt->pgport,
+			                          vopt->username, 1,
+			                          vopt->progname, false);
+
+			/* close read end of Worker -> Master */
+			closesocket(pipeWM[PIPE_READ]);
+			/* close write end of Master -> Worker */
+			closesocket(pipeMW[PIPE_WRITE]);
+
+			/*
+			 * Close all inherited fds for communication of the master with
+			 * the other workers.
+			 */
+			for (j = 0; j < i; j++)
+			{
+				closesocket(pstate->parallelSlot[j].pipeRead);
+				closesocket(pstate->parallelSlot[j].pipeWrite);
+			}
+
+			SetupWorker(pstate->parallelSlot[i].args->connection, pipefd, i);
+			exit(0);
+		}
+		else if (pid < 0)
+			/* fork failed */
+			exit_horribly(modulename,
+						  "could not create worker process: %s\n",
+						  strerror(errno));
+
+		/* we are the Master, pid > 0 here */
+		Assert(pid > 0);
+
+		/* close read end of Master -> Worker */
+		closesocket(pipeMW[PIPE_READ]);
+		/* close write end of Worker -> Master */
+		closesocket(pipeWM[PIPE_WRITE]);
+
+		pstate->parallelSlot[i].pid = pid;
+#endif
+
+		pstate->parallelSlot[i].pipeRead = pipeWM[PIPE_READ];
+		pstate->parallelSlot[i].pipeWrite = pipeMW[PIPE_WRITE];
+	}
+
+	return pstate;
+}
+
+/*
+ * Tell all of our workers to terminate.
+ *
+ * Pretty straightforward routine, first we tell everyone to terminate, then
+ * we listen to the workers' replies and finally close the sockets that we
+ * have used for communication.
+ */
+void
+ParallelVacuumEnd(ParallelState *pstate)
+{
+	int			i;
+
+	if (pstate->numWorkers == 1)
+		return;
+
+	Assert(IsEveryWorkerIdle(pstate));
+
+	/* close the sockets so that the workers know they can exit */
+	for (i = 0; i < pstate->numWorkers; i++)
+	{
+		closesocket(pstate->parallelSlot[i].pipeRead);
+		closesocket(pstate->parallelSlot[i].pipeWrite);
+	}
+
+	WaitForTerminatingWorkers(pstate);
+
+	/*
+	 * Remove the pstate again, so the exit handler in the parent will now
+	 * again fall back to closing AH->connection (if connected).
+	 */
+	shutdown_info.pstate = NULL;
+
+	free(pstate->parallelSlot);
+	free(pstate);
+}
+
+
+/*
+ * Find the first free parallel slot (if any).
+ */
+int
+GetIdleWorker(ParallelState *pstate)
+{
+	int			i;
+
+	for (i = 0; i < pstate->numWorkers; i++)
+		if (pstate->parallelSlot[i].workerStatus == WRKR_IDLE)
+			return i;
+	return NO_SLOT;
+}
+
+/*
+ * Return true iff every worker process is in the WRKR_TERMINATED state.
+ */
+static bool
+HasEveryWorkerTerminated(ParallelState *pstate)
+{
+	int			i;
+
+	for (i = 0; i < pstate->numWorkers; i++)
+		if (pstate->parallelSlot[i].workerStatus != WRKR_TERMINATED)
+			return false;
+	return true;
+}
+
+
+
+/*
+ * This function is called by both UNIX and Windows variants to set up a
+ * worker process.
+ */
+static void
+SetupWorker(PGconn *connection, int pipefd[2], int worker)
+{
+	/*
+	 * Call the setup worker function that's defined in the ArchiveHandle.
+	 *
+	 * We get the raw connection only for the reason that we can close it
+	 * properly when we shut down. This happens only that way when it is
+	 * brought down because of an error.
+	 */
+	WaitForCommands(connection, pipefd);
+	closesocket(pipefd[PIPE_READ]);
+	closesocket(pipefd[PIPE_WRITE]);
+}
+
+
+
+/*
+ * That's the main routine for the worker.
+ * When it starts up it enters this routine and waits for commands from the
+ * master process. After having processed a command it comes back to here to
+ * wait for the next command. Finally it will receive a TERMINATE command and
+ * exit.
+ */
+static void
+WaitForCommands(PGconn * connection, int pipefd[2])
+{
+	char	   *command;
+
+	for (;;)
+	{
+		if (!(command = getMessageFromMaster(pipefd)))
+		{
+			PQfinish(connection);
+			connection = NULL;
+			return;
+		}
+
+		/*
+		 * The message we return here has been pg_malloc()ed and we are
+		 * responsible for free()ing it.
+		 */
+		if (executeMaintenanceCommand(connection, command, false))
+            sendMessageToMaster(pipefd, "OK");
+        else
+            sendMessageToMaster(pipefd, "ERROR  : Execute failed");
+
+		/* command was pg_malloc'd and we are responsible for free()ing it. */
+		free(command);
+	}
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * Note the status change:
+ *
+ * DispatchJobForTocEntry		WRKR_IDLE -> WRKR_WORKING
+ * ListenToWorkers				WRKR_WORKING -> WRKR_FINISHED / WRKR_TERMINATED
+ * ReapWorkerStatus				WRKR_FINISHED -> WRKR_IDLE
+ * ---------------------------------------------------------------------
+ *
+ * Just calling ReapWorkerStatus() when all workers are working might or might
+ * not give you an idle worker because you need to call ListenToWorkers() in
+ * between and only thereafter ReapWorkerStatus(). This is necessary in order
+ * to get and deal with the status (=result) of the worker's execution.
+ */
+void
+ListenToWorkers(ParallelState *pstate, bool do_wait)
+{
+	int			worker;
+	char	   *msg;
+
+	msg = getMessageFromWorker(pstate, do_wait, &worker);
+
+	if (!msg)
+	{
+		if (do_wait)
+			exit_horribly(modulename, "a worker process died unexpectedly\n");
+		return;
+	}
+
+	if (messageStartsWith(msg, "OK"))
+	{
+		pstate->parallelSlot[worker].workerStatus = WRKR_FINISHED;
+
+	}
+	else if (messageStartsWith(msg, "ERROR "))
+	{
+		pstate->parallelSlot[worker].workerStatus = WRKR_TERMINATED;
+		exit_horribly(modulename, "%s", msg + strlen("ERROR "));
+	}
+	else
+		exit_horribly(modulename, "invalid message received from worker: %s\n", msg);
+
+	/* both Unix and Win32 return pg_malloc()ed space, so we free it */
+	free(msg);
+}
+
+/*
+ * This function is executed in the master process.
+ *
+ * This function is used to get the return value of a terminated worker
+ * process. If a process has terminated, its status is stored in *status and
+ * the id of the worker is returned.
+ */
+int
+ReapWorkerStatus(ParallelState *pstate, int *status)
+{
+	int			i;
+
+	for (i = 0; i < pstate->numWorkers; i++)
+	{
+		if (pstate->parallelSlot[i].workerStatus == WRKR_FINISHED)
+		{
+			*status = pstate->parallelSlot[i].status;
+			pstate->parallelSlot[i].status = 0;
+			pstate->parallelSlot[i].workerStatus = WRKR_IDLE;
+			return i;
+		}
+	}
+
+	return NO_SLOT;
+}
+
+/*
+ * This function is executed in the master process.
+ *
+ * It looks for an idle worker process and only returns if there is one.
+ */
+void
+EnsureIdleWorker(ParallelState *pstate)
+{
+	int			ret_worker;
+	int			work_status;
+
+	for (;;)
+	{
+		int			nTerm = 0;
+
+		while ((ret_worker = ReapWorkerStatus(pstate, &work_status)) != NO_SLOT)
+		{
+			if (work_status != 0)
+				exit_horribly(modulename, "error processing a parallel work item\n");
+
+			nTerm++;
+		}
+
+		/*
+		 * We need to make sure that we have an idle worker before dispatching
+		 * the next item. If nTerm > 0 we already have that (quick check).
+		 */
+		if (nTerm > 0)
+			return;
+
+		/* explicit check for an idle worker */
+		if (GetIdleWorker(pstate) != NO_SLOT)
+			return;
+
+		/*
+		 * If we have no idle worker, read the result of one or more workers
+		 * and loop the loop to call ReapWorkerStatus() on them
+		 */
+		ListenToWorkers(pstate, true);
+	}
+}
+
+
+/*
+ * Return true iff every worker is in the WRKR_IDLE state.
+ */
+bool
+IsEveryWorkerIdle(ParallelState *pstate)
+{
+	int			i;
+
+	for (i = 0; i < pstate->numWorkers; i++)
+		if (pstate->parallelSlot[i].workerStatus != WRKR_IDLE)
+			return false;
+	return true;
+}
+
+
+/*
+ * This function is executed in the master process.
+ *
+ * It waits for all workers to terminate.
+ */
+void
+EnsureWorkersFinished(ParallelState *pstate)
+{
+	int			work_status;
+
+	if (!pstate || pstate->numWorkers == 1)
+		return;
+
+	/* Waiting for the remaining worker processes to finish */
+	while (!IsEveryWorkerIdle(pstate))
+	{
+		if (ReapWorkerStatus(pstate, &work_status) == NO_SLOT)
+			ListenToWorkers(pstate, true);
+		else if (work_status != 0)
+			exit_horribly(modulename,
+						  "error processing a parallel work item\n");
+	}
+}
+
+/*
+ * This function is executed in the worker process.
+ *
+ * It returns the next message on the communication channel, blocking until it
+ * becomes available.
+ */
+static char *
+getMessageFromMaster(int pipefd[2])
+{
+	return readMessageFromPipe(pipefd[PIPE_READ]);
+}
+
+/*
+ * This function is executed in the worker process.
+ *
+ * It sends a message to the master on the communication channel.
+ */
+static void
+sendMessageToMaster(int pipefd[2], const char *str)
+{
+	int			len = strlen(str) + 1;
+
+	if (pipewrite(pipefd[PIPE_WRITE], str, len) != len)
+		exit_horribly(modulename,
+					  "could not write to the communication channel: %s\n",
+					  strerror(errno));
+}
+
+/*
+ * This function is executed in the master process.
+ *
+ * It returns the next message from the worker on the communication channel,
+ * optionally blocking (do_wait) until it becomes available.
+ *
+ * The id of the worker is returned in *worker.
+ */
+static char *
+getMessageFromWorker(ParallelState *pstate, bool do_wait, int *worker)
+{
+	int			i;
+	fd_set		workerset;
+	int			maxFd = -1;
+	struct timeval nowait = {0, 0};
+
+	FD_ZERO(&workerset);
+
+	for (i = 0; i < pstate->numWorkers; i++)
+	{
+		if (pstate->parallelSlot[i].workerStatus == WRKR_TERMINATED)
+			continue;
+		FD_SET(pstate->parallelSlot[i].pipeRead, &workerset);
+		/* actually WIN32 ignores the first parameter to select()... */
+		if (pstate->parallelSlot[i].pipeRead > maxFd)
+			maxFd = pstate->parallelSlot[i].pipeRead;
+	}
+
+	if (do_wait)
+	{
+		i = select_loop(maxFd, &workerset);
+		Assert(i != 0);
+	}
+	else
+	{
+		if ((i = select(maxFd + 1, &workerset, NULL, NULL, &nowait)) == 0)
+			return NULL;
+	}
+
+	if (i < 0)
+		exit_horribly(modulename, "error in ListenToWorkers(): %s\n", strerror(errno));
+
+	for (i = 0; i < pstate->numWorkers; i++)
+	{
+		char	   *msg;
+
+		if (!FD_ISSET(pstate->parallelSlot[i].pipeRead, &workerset))
+			continue;
+
+		msg = readMessageFromPipe(pstate->parallelSlot[i].pipeRead);
+		*worker = i;
+		return msg;
+	}
+
+	Assert(false);
+	return NULL;
+}
+
+/*
+ * This function is executed in the master process.
+ *
+ * It sends a message to a certain worker on the communication channel.
+ */
+static void
+sendMessageToWorker(ParallelState *pstate, int worker, const char *str)
+{
+	int			len = strlen(str) + 1;
+
+	if (pipewrite(pstate->parallelSlot[worker].pipeWrite, str, len) != len)
+	{
+		/*
+		 * If we're already aborting anyway, don't care if we succeed or not.
+		 * The child might have gone already.
+		 */
+#ifndef WIN32
+		if (!aborting)
+#endif
+			exit_horribly(modulename,
+						  "could not write to the communication channel: %s\n",
+						  strerror(errno));
+	}
+}
+
+/*
+ * The underlying function to read a message from the communication channel
+ * (fd) with optional blocking (do_wait).
+ */
+static char *
+readMessageFromPipe(int fd)
+{
+	char	   *msg;
+	int			msgsize,
+				bufsize;
+	int			ret;
+
+	/*
+	 * The problem here is that we need to deal with several possibilites: we
+	 * could receive only a partial message or several messages at once. The
+	 * caller expects us to return exactly one message however.
+	 *
+	 * We could either read in as much as we can and keep track of what we
+	 * delivered back to the caller or we just read byte by byte. Once we see
+	 * (char) 0, we know that it's the message's end. This would be quite
+	 * inefficient for more data but since we are reading only on the command
+	 * channel, the performance loss does not seem worth the trouble of
+	 * keeping internal states for different file descriptors.
+	 */
+	bufsize = 64;				/* could be any number */
+	msg = (char *) pg_malloc(bufsize);
+
+	msgsize = 0;
+	for (;;)
+	{
+		Assert(msgsize <= bufsize);
+		ret = piperead(fd, msg + msgsize, 1);
+
+		/* worker has closed the connection or another error happened */
+		if (ret <= 0)
+			return NULL;
+
+		Assert(ret == 1);
+
+		if (msg[msgsize] == '\0')
+			return msg;
+
+		msgsize++;
+		if (msgsize == bufsize)
+		{
+			/* could be any number */
+			bufsize += 16;
+			msg = (char *) realloc(msg, bufsize);
+		}
+	}
+}
+
+/*
+ * A select loop that repeats calling select until a descriptor in the read
+ * set becomes readable. On Windows we have to check for the termination event
+ * from time to time, on Unix we can just block forever.
+ */
+static int
+select_loop(int maxFd, fd_set *workerset)
+{
+	int			i;
+	fd_set		saveSet = *workerset;
+
+#ifdef WIN32
+	/* should always be the master */
+	Assert(tMasterThreadId == GetCurrentThreadId());
+
+	for (;;)
+	{
+		/*
+		 * sleep a quarter of a second before checking if we should terminate.
+		 */
+		struct timeval tv = {0, 250000};
+
+		*workerset = saveSet;
+		i = select(maxFd + 1, workerset, NULL, NULL, &tv);
+
+		if (i == SOCKET_ERROR && WSAGetLastError() == WSAEINTR)
+			continue;
+		if (i)
+			break;
+	}
+#else							/* UNIX */
+
+	for (;;)
+	{
+		*workerset = saveSet;
+		i = select(maxFd + 1, workerset, NULL, NULL, NULL);
+
+		/*
+		 * If we Ctrl-C the master process , it's likely that we interrupt
+		 * select() here. The signal handler will set wantAbort == true and
+		 * the shutdown journey starts from here. Note that we'll come back
+		 * here later when we tell all workers to terminate and read their
+		 * responses. But then we have aborting set to true.
+		 */
+		if (wantAbort && !aborting)
+			exit_horribly(modulename, "terminated by user\n");
+
+		if (i < 0 && errno == EINTR)
+			continue;
+		break;
+	}
+#endif
+
+	return i;
+}
+
+void
+DispatchJob(ParallelState *pstate, char * command)
+{
+	int			worker;
+
+	/* our caller makes sure that at least one worker is idle */
+	Assert(GetIdleWorker(pstate) != NO_SLOT);
+	worker = GetIdleWorker(pstate);
+	Assert(worker != NO_SLOT);
+
+	sendMessageToWorker(pstate, worker, command);
+	pstate->parallelSlot[worker].workerStatus = WRKR_WORKING;
+}
+
+#ifdef WIN32
+/*
+ * This is a replacement version of pipe for Win32 which allows returned
+ * handles to be used in select(). Note that read/write calls must be replaced
+ * with recv/send.
+ */
+static int
+pgpipe(int handles[2])
+{
+	SOCKET		s;
+	struct sockaddr_in serv_addr;
+	int			len = sizeof(serv_addr);
+
+	handles[0] = handles[1] = INVALID_SOCKET;
+
+	if ((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
+	{
+		return -1;
+	}
+
+	memset((void *) &serv_addr, 0, sizeof(serv_addr));
+	serv_addr.sin_family = AF_INET;
+	serv_addr.sin_port = htons(0);
+	serv_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+	if (bind(s, (SOCKADDR *) &serv_addr, len) == SOCKET_ERROR)
+	{
+		closesocket(s);
+		return -1;
+	}
+	if (listen(s, 1) == SOCKET_ERROR)
+	{
+		closesocket(s);
+		return -1;
+	}
+	if (getsockname(s, (SOCKADDR *) &serv_addr, &len) == SOCKET_ERROR)
+	{
+		closesocket(s);
+		return -1;
+	}
+	if ((handles[1] = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
+	{
+		closesocket(s);
+		return -1;
+	}
+
+	if (connect(handles[1], (SOCKADDR *) &serv_addr, len) == SOCKET_ERROR)
+	{
+		closesocket(s);
+		return -1;
+	}
+	if ((handles[0] = accept(s, (SOCKADDR *) &serv_addr, &len)) == INVALID_SOCKET)
+	{
+		closesocket(handles[1]);
+		handles[1] = INVALID_SOCKET;
+		closesocket(s);
+		return -1;
+	}
+	closesocket(s);
+	return 0;
+}
+
+static int
+piperead(int s, char *buf, int len)
+{
+	int			ret = recv(s, buf, len, 0);
+
+	if (ret < 0 && WSAGetLastError() == WSAECONNRESET)
+		/* EOF on the pipe! (win32 socket based implementation) */
+		ret = 0;
+	return ret;
+}
+
+#endif
+
+static void
+shutdown_parallel_vacuum_utils()
+{
+#ifdef WIN32
+	/* Call the cleanup function only from the main thread */
+	if (mainThreadId == GetCurrentThreadId())
+		WSACleanup();
+#endif
+}
+
+void
+init_parallel_vacuum_utils(void)
+{
+#ifdef WIN32
+	if (!parallel_init_done)
+	{
+		WSADATA		wsaData;
+		int			err;
+
+		mainThreadId = GetCurrentThreadId();
+		err = WSAStartup(MAKEWORD(2, 2), &wsaData);
+		if (err != 0)
+		{
+			exit_nicely(1);
+		}
+		parallel_init_done = true;
+	}
+#endif
+}
+
+void
+on_exit_close_connection(PGconn *conn)
+{
+	shutdown_info.conn = conn;
+}
+
+/*
+ * 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);
+
+    slot = GetMyPSlot(pstate);
+    if (!slot)
+    {
+        /* We're the parent, just write the message out */
+        vfprintf(stderr, _(fmt), ap);
+        ParallelVacuumEnd(pstate);
+        PQfinish(shutdown_info.conn);
+    }
+    else
+    {
+        /* If we're a worker process, send the msg to the master process */
+        parallel_msg_master(slot, modulename, fmt, ap);
+        PQfinish(slot->args->connection);
+    }
+
+    va_end(ap);
+    exit_nicely(1);
+}
+
+static void
+exit_nicely(int code)
+{
+    shutdown_parallel_vacuum_utils();
+	exit(code);
+}
+
+
diff --git a/src/bin/scripts/vac_parallel.h b/src/bin/scripts/vac_parallel.h
new file mode 100644
index 0000000..21100b1
--- /dev/null
+++ b/src/bin/scripts/vac_parallel.h
@@ -0,0 +1,102 @@
+/*-------------------------------------------------------------------------
+ *
+ * vac_parallel.h
+ *
+ *	Parallel support header file for the vacuumdb
+ *
+ * Portions Copyright (c) 1996-2011, 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/scripts/vac_parallel.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef VAC_PARALLEL_H
+#define VAC_PARALLEL_H
+
+#include "postgres_fe.h"
+#include <time.h>
+#include "libpq-fe.h"
+
+
+typedef enum
+{
+	WRKR_TERMINATED = 0,
+	WRKR_IDLE,
+	WRKR_WORKING,
+	WRKR_FINISHED
+} T_WorkerStatus;
+
+/* Arguments needed for a worker process */
+typedef struct ParallelArgs
+{
+	PGconn *connection;
+} ParallelArgs;
+
+/* State for each parallel activity slot */
+typedef struct ParallelSlot
+{
+	ParallelArgs *args; //can pass connection handle here
+	T_WorkerStatus workerStatus;
+	int			status;
+	int			pipeRead;
+	int			pipeWrite;
+	int			pipeRevRead;
+	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;
+
+
+
+typedef struct VacuumOption
+{
+	char	   *dbname;
+	char	   *pgport;
+	char	   *pghost;
+	char	   *username;
+	char * progname;
+}VacuumOption;
+
+
+#ifdef WIN32
+extern bool parallel_init_done;
+extern DWORD mainThreadId;
+#endif
+
+extern ParallelState * ParallelVacuumStart(VacuumOption *vopt, int numWorkers);
+extern int	GetIdleWorker(ParallelState *pstate);
+extern bool IsEveryWorkerIdle(ParallelState *pstate);
+extern void ListenToWorkers(ParallelState *pstate, bool do_wait);
+extern int	ReapWorkerStatus(ParallelState *pstate, int *status);
+extern void EnsureIdleWorker(ParallelState *pstate);
+extern void EnsureWorkersFinished(ParallelState *pstate);
+
+extern void DispatchJob(ParallelState *pstate, char * command);
+extern void
+exit_horribly(const char *modulename, const char *fmt,...)
+__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3), noreturn));
+
+extern void init_parallel_vacuum_utils(void);
+extern  void on_exit_close_connection(PGconn *conn);
+extern void ParallelVacuumEnd(ParallelState *pstate);
+
+
+#endif   /* VAC_PARALLEL_H */
diff --git a/src/bin/scripts/vacuumdb.c b/src/bin/scripts/vacuumdb.c
index e4dde1f..4d43ae9 100644
--- a/src/bin/scripts/vacuumdb.c
+++ b/src/bin/scripts/vacuumdb.c
@@ -13,6 +13,7 @@
 #include "postgres_fe.h"
 #include "common.h"
 #include "dumputils.h"
+#include "vac_parallel.h"
 
 
 static void vacuum_one_database(const char *dbname, bool full, bool verbose,
@@ -29,6 +30,18 @@ static void vacuum_all_databases(bool full, bool verbose, bool and_analyze,
 
 static void help(const char *progname);
 
+void vacuum_parallel(const char *dbname, bool full, bool verbose,
+					bool and_analyze, bool analyze_only, bool freeze,
+					const char *table, const char *host, const char *port,
+					const char *username, enum trivalue prompt_password,
+					const char *progname, bool echo, int parallel,
+					SimpleStringList *tables);
+
+void run_command(ParallelState *pstate, char *command);
+
+void prepare_command(PGconn *conn, bool full, bool verbose, bool and_analyze,
+                     bool analyze_only, bool freeze, PQExpBuffer sql);
+
 
 int
 main(int argc, char *argv[])
@@ -49,6 +62,7 @@ main(int argc, char *argv[])
 		{"table", required_argument, NULL, 't'},
 		{"full", no_argument, NULL, 'f'},
 		{"verbose", no_argument, NULL, 'v'},
+		{"parallel", required_argument, NULL, 'j'},
 		{"maintenance-db", required_argument, NULL, 2},
 		{NULL, 0, NULL, 0}
 	};
@@ -72,13 +86,14 @@ main(int argc, char *argv[])
 	bool		full = false;
 	bool		verbose = false;
 	SimpleStringList tables = {NULL, NULL};
+    int parallel = 0;
 
 	progname = get_progname(argv[0]);
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
 
 	handle_help_version_opts(argc, argv, "vacuumdb", help);
 
-	while ((c = getopt_long(argc, argv, "h:p:U:wWeqd:zZFat:fv", long_options, &optindex)) != -1)
+	while ((c = getopt_long(argc, argv, "h:p:U:wWeqd:zZFat:fv:j:", long_options, &optindex)) != -1)
 	{
 		switch (c)
 		{
@@ -127,6 +142,9 @@ main(int argc, char *argv[])
 			case 'v':
 				verbose = true;
 				break;
+            case 'j':
+                parallel = atoi(optarg);
+                break;
 			case 2:
 				maintenance_db = pg_strdup(optarg);
 				break;
@@ -136,6 +154,7 @@ main(int argc, char *argv[])
 		}
 	}
 
+    optind++;
 
 	/*
 	 * Non-option argument specifies database name as long as it wasn't
@@ -209,21 +228,49 @@ main(int argc, char *argv[])
 		{
 			SimpleStringListCell *cell;
 
-			for (cell = tables.head; cell; cell = cell->next)
-			{
-				vacuum_one_database(dbname, full, verbose, and_analyze,
-									analyze_only,
-									freeze, cell->val,
-									host, port, username, prompt_password,
-									progname, echo);
-			}
+            if (parallel < 2)
+            {
+    			for (cell = tables.head; cell; cell = cell->next)
+    			{
+    				vacuum_one_database(dbname, full, verbose, and_analyze,
+    									analyze_only,
+    									freeze, cell->val,
+    									host, port, username, prompt_password,
+    									progname, echo);
+    			}
+            }
+            else
+            {
+                vacuum_parallel(dbname, full, verbose, and_analyze,
+    								analyze_only,
+    								freeze, NULL,
+    								host, port, username, prompt_password,
+    								progname, echo, parallel, &tables);
+
+            }
 		}
 		else
-			vacuum_one_database(dbname, full, verbose, and_analyze,
-								analyze_only,
-								freeze, NULL,
-								host, port, username, prompt_password,
-								progname, echo);
+		{
+
+            if (parallel < 2)
+            {
+    			vacuum_one_database(dbname, full, verbose, and_analyze,
+    								analyze_only,
+    								freeze, NULL,
+    								host, port, username, prompt_password,
+    								progname, echo);
+            }
+            else
+            {
+
+                vacuum_parallel(dbname, full, verbose, and_analyze,
+    								analyze_only,
+    								freeze, NULL,
+    								host, port, username, prompt_password,
+    								progname, echo, parallel, NULL);
+            }
+	    }
+
 	}
 
 	exit(0);
@@ -351,6 +398,173 @@ vacuum_all_databases(bool full, bool verbose, bool and_analyze, bool analyze_onl
 }
 
 
+void
+vacuum_parallel(const char *dbname, bool full, bool verbose,
+					bool and_analyze, bool analyze_only, bool freeze,
+					const char *table, const char *host, const char *port,
+					const char *username, enum trivalue prompt_password,
+					const char *progname, bool echo, int parallel,
+					SimpleStringList *tables)
+{
+	PQExpBufferData sql;
+
+	PGconn	   *conn;
+    PGresult *res;
+    int ntuple;
+    int i;
+    char *relName;
+    char *nspace;
+    VacuumOption vopt;
+    ParallelState *pstate;
+
+    init_parallel_vacuum_utils();
+
+	initPQExpBuffer(&sql);
+
+	conn = connectDatabase(dbname, host, port, username, prompt_password,
+						   progname, false);
+
+    vopt.dbname = dbname;
+    vopt.pghost = host;
+    vopt.pgport = port;
+    vopt.username = username;
+    vopt.progname = progname;
+
+    on_exit_close_connection(conn);
+
+    pstate = ParallelVacuumStart(&vopt, parallel);
+
+    if (tables == NULL)
+    {
+        res = executeQuery(conn,
+            "select relname, nspname from pg_class c, pg_namespace ns"
+            " where relkind= \'r\' and c.relnamespace = ns.oid",
+            progname, echo);
+
+        ntuple = PQntuples(res);
+        for (i = 0; i < ntuple; i++)
+        {
+            relName = PQgetvalue(res, i, 0);
+            nspace = PQgetvalue(res, i, 1);
+            prepare_command(conn, full, verbose, and_analyze,
+                            analyze_only, freeze, &sql);
+
+            appendPQExpBuffer(&sql, " %s.%s", nspace, relName);
+            run_command(pstate, sql.data);
+            termPQExpBuffer(&sql);
+        }
+    }
+    else
+    {
+        SimpleStringListCell *cell;
+
+        for (cell = tables->head; cell; cell = cell->next)
+        {
+            prepare_command(conn, full, verbose, and_analyze,
+                            analyze_only, freeze, &sql);
+            appendPQExpBuffer(&sql, " %s", cell->val);
+            run_command(pstate, sql.data);
+            termPQExpBuffer(&sql);
+        }
+    }
+
+    EnsureWorkersFinished(pstate);
+    ParallelVacuumEnd(pstate);
+
+	PQfinish(conn);
+	termPQExpBuffer(&sql);
+}
+
+void run_command(ParallelState *pstate, char *command)
+{
+    int work_status;
+    int ret_child;
+
+	DispatchJob(pstate, command);
+
+    /*Listen for worker and get message*/
+    for (;;)
+    {
+        int         nTerm = 0;
+
+        ListenToWorkers(pstate, false);
+        while ((ret_child = ReapWorkerStatus(pstate, &work_status)) != NO_SLOT)
+        {
+            nTerm++;
+        }
+
+        /*
+         * We need to make sure that we have an idle worker before
+         * re-running the loop. If nTerm > 0 we already have that (quick
+         * check).
+         */
+        if (nTerm > 0)
+            break;
+
+        /* if nobody terminated, explicitly check for an idle worker */
+        if (GetIdleWorker(pstate) != NO_SLOT)
+            break;
+    }
+}
+
+void prepare_command(PGconn *conn, bool full, bool verbose, bool and_analyze,
+                     bool analyze_only, bool freeze, PQExpBuffer sql)
+{
+	initPQExpBuffer(sql);
+
+	if (analyze_only)
+	{
+		appendPQExpBuffer(sql, "ANALYZE");
+		if (verbose)
+			appendPQExpBuffer(sql, " VERBOSE");
+	}
+	else
+	{
+		appendPQExpBuffer(sql, "VACUUM");
+		if (PQserverVersion(conn) >= 90000)
+		{
+			const char *paren = " (";
+			const char *comma = ", ";
+			const char *sep = paren;
+
+			if (full)
+			{
+				appendPQExpBuffer(sql, "%sFULL", sep);
+				sep = comma;
+			}
+			if (freeze)
+			{
+				appendPQExpBuffer(sql, "%sFREEZE", sep);
+				sep = comma;
+			}
+			if (verbose)
+			{
+				appendPQExpBuffer(sql, "%sVERBOSE", sep);
+				sep = comma;
+			}
+			if (and_analyze)
+			{
+				appendPQExpBuffer(sql, "%sANALYZE", sep);
+				sep = comma;
+			}
+			if (sep != paren)
+				appendPQExpBuffer(sql, ")");
+		}
+		else
+		{
+			if (full)
+				appendPQExpBuffer(sql, " FULL");
+			if (freeze)
+				appendPQExpBuffer(sql, " FREEZE");
+			if (verbose)
+				appendPQExpBuffer(sql, " VERBOSE");
+			if (and_analyze)
+				appendPQExpBuffer(sql, " ANALYZE");
+		}
+	}
+}
+
+
 static void
 help(const char *progname)
 {
