From a6f005d9ea81e1a989353f320149e12281e9fb04 Mon Sep 17 00:00:00 2001
From: Mike Palmiotto <mike.palmiotto@crunchydata.com>
Date: Fri, 27 Sep 2019 16:45:57 -0400
Subject: [PATCH 2/8] Add centralized autovac launcher/worker

---
 src/backend/postmaster/autovacuum.c   | 157 ++++----------------------
 src/backend/postmaster/postmaster.c   |  67 ++++++-----
 src/include/postmaster/autovacuum.h   |   9 +-
 src/include/postmaster/fork_process.h |   2 +
 4 files changed, 70 insertions(+), 165 deletions(-)

diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 073f313337..5c3ac1568f 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -134,8 +134,8 @@ int			Log_autovacuum_min_duration = -1;
 #define MAX_AUTOVAC_SLEEPTIME 300	/* seconds */
 
 /* Flags to tell if we are in an autovacuum process */
-static bool am_autovacuum_launcher = false;
-static bool am_autovacuum_worker = false;
+bool am_autovacuum_launcher = false;
+bool am_autovacuum_worker = false;
 
 /* Flags set by signal handlers */
 static volatile sig_atomic_t got_SIGHUP = false;
@@ -303,10 +303,6 @@ static WorkerInfo MyWorkerInfo = NULL;
 /* PID of launcher, valid only in worker while shutting down */
 int			AutovacuumLauncherPid = 0;
 
-#ifdef EXEC_BACKEND
-static pid_t avlauncher_forkexec(void);
-static pid_t avworker_forkexec(void);
-#endif
 NON_EXEC_STATIC void AutoVacWorkerMain(int argc, char *argv[]) pg_attribute_noreturn();
 NON_EXEC_STATIC void AutoVacLauncherMain(int argc, char *argv[]) pg_attribute_noreturn();
 
@@ -347,88 +343,53 @@ static void avl_sigusr2_handler(SIGNAL_ARGS);
 static void avl_sigterm_handler(SIGNAL_ARGS);
 static void autovac_refresh_stats(void);
 
-
-
 /********************************************************************
  *					  AUTOVACUUM LAUNCHER CODE
  ********************************************************************/
 
-#ifdef EXEC_BACKEND
 /*
- * forkexec routine for the autovacuum launcher process.
+ * PrepAutoVacProcessFork
  *
  * Format up the arglist, then fork and exec.
  */
-static pid_t
-avlauncher_forkexec(void)
+void
+PrepAutoVacProcessFork(ForkProcData *autovac_fork)
 {
-	char	   *av[10];
 	int			ac = 0;
 
-	av[ac++] = "postgres";
-	av[ac++] = "--forkavlauncher";
-	av[ac++] = NULL;			/* filled in by postmaster_forkexec */
-	av[ac] = NULL;
-
-	Assert(ac < lengthof(av));
-
-	return postmaster_forkexec(ac, av);
-}
-
 /*
- * We need this set from the outside, before InitProcess is called
+	 * Set up command-line arguments for subprocess
  */
-void
-AutovacuumLauncherIAm(void)
-{
-	am_autovacuum_launcher = true;
-}
-#endif
+	autovac_fork->av[ac++] = pstrdup("postgres");
 
-/*
- * Main entry point for autovacuum launcher process, to be called from the
- * postmaster.
- */
-int
-StartAutoVacLauncher(void)
+	if (MyForkProcType == AutoVacLauncherFork)
 {
-	pid_t		AutoVacPID;
-
+		autovac_fork->type_desc = pstrdup("autovacuum launcher");
+		autovac_fork->child_main = AutoVacLauncherMain;
 #ifdef EXEC_BACKEND
-	switch ((AutoVacPID = avlauncher_forkexec()))
-#else
-	switch ((AutoVacPID = fork_process()))
+		autovac_fork->av[ac++] = pstrdup("--forkavlauncher");
+		autovac_fork->av[ac++] = NULL;		  /* filled in by postmaster_forkexec */
 #endif
+	}
+	else if (MyForkProcType == AutoVacWorkerFork)
 	{
-		case -1:
-			ereport(LOG,
-					(errmsg("could not fork autovacuum launcher process: %m")));
-			return 0;
-
-#ifndef EXEC_BACKEND
-		case 0:
-			/* in postmaster child ... */
-			InitPostmasterChild();
-
-			/* Close the postmaster's sockets */
-			ClosePostmasterPorts(false);
-
-			AutoVacLauncherMain(0, NULL);
-			break;
+		autovac_fork->type_desc = pstrdup("autovacuum worker");
+		autovac_fork->child_main = AutoVacWorkerMain;
+#ifdef EXEC_BACKEND
+		autovac_fork->av[ac++] = pstrdup("--forkavworker");
+		autovac_fork->av[ac++] = NULL;		  /* filled in by postmaster_forkexec */
 #endif
-		default:
-			return (int) AutoVacPID;
 	}
 
-	/* shouldn't get here */
-	return 0;
+	autovac_fork->ac = ac;
+	Assert(autovac_fork->ac < lengthof(*autovac_fork->av));
 }
 
 /*
  * Main loop for the autovacuum launcher process.
  */
 NON_EXEC_STATIC void
-AutoVacLauncherMain(int argc, char *argv[])
+AutoVacLauncherMain(pg_attribute_unused() int argc, pg_attribute_unused() char *argv[])
 {
 	sigjmp_buf	local_sigjmp_buf;
 
@@ -1428,83 +1389,11 @@ avl_sigterm_handler(SIGNAL_ARGS)
  *					  AUTOVACUUM WORKER CODE
  ********************************************************************/
 
-#ifdef EXEC_BACKEND
-/*
- * forkexec routines for the autovacuum worker.
- *
- * Format up the arglist, then fork and exec.
- */
-static pid_t
-avworker_forkexec(void)
-{
-	char	   *av[10];
-	int			ac = 0;
-
-	av[ac++] = "postgres";
-	av[ac++] = "--forkavworker";
-	av[ac++] = NULL;			/* filled in by postmaster_forkexec */
-	av[ac] = NULL;
-
-	Assert(ac < lengthof(av));
-
-	return postmaster_forkexec(ac, av);
-}
-
-/*
- * We need this set from the outside, before InitProcess is called
- */
-void
-AutovacuumWorkerIAm(void)
-{
-	am_autovacuum_worker = true;
-}
-#endif
-
-/*
- * Main entry point for autovacuum worker process.
- *
- * This code is heavily based on pgarch.c, q.v.
- */
-int
-StartAutoVacWorker(void)
-{
-	pid_t		worker_pid;
-
-#ifdef EXEC_BACKEND
-	switch ((worker_pid = avworker_forkexec()))
-#else
-	switch ((worker_pid = fork_process()))
-#endif
-	{
-		case -1:
-			ereport(LOG,
-					(errmsg("could not fork autovacuum worker process: %m")));
-			return 0;
-
-#ifndef EXEC_BACKEND
-		case 0:
-			/* in postmaster child ... */
-			InitPostmasterChild();
-
-			/* Close the postmaster's sockets */
-			ClosePostmasterPorts(false);
-
-			AutoVacWorkerMain(0, NULL);
-			break;
-#endif
-		default:
-			return (int) worker_pid;
-	}
-
-	/* shouldn't get here */
-	return 0;
-}
-
 /*
  * AutoVacWorkerMain
  */
 NON_EXEC_STATIC void
-AutoVacWorkerMain(int argc, char *argv[])
+AutoVacWorkerMain(pg_attribute_unused() int argc, pg_attribute_unused() char *argv[])
 {
 	sigjmp_buf	local_sigjmp_buf;
 	Oid			dbid;
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index e0d11cc6ab..35cd1479b9 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -414,6 +414,9 @@ static bool RandomCancelKey(int32 *cancel_key);
 static void signal_child(pid_t pid, int signal);
 static bool SignalSomeChildren(int signal, int targets);
 static void TerminateChildren(int signal);
+#ifdef EXEC_BACKEND
+static void shmemSetup(bool aux_process);
+#endif
 
 #define SignalChildren(sig)			   SignalSomeChildren(sig, BACKEND_TYPE_ALL)
 
@@ -544,6 +547,8 @@ static void ShmemBackendArrayRemove(Backend *bn);
 #define StartCheckpointer()		StartChildProcess(CheckpointerFork)
 #define StartWalWriter()		StartChildProcess(WalWriterFork)
 #define StartWalReceiver()		StartChildProcess(WalReceiverFork)
+#define StartAutoVacLauncher()		StartChildProcess(AutoVacLauncherFork)
+#define StartAutoVacWorker()		StartChildProcess(AutoVacWorkerFork)
 
 /* Macros to check exit status of a child process */
 #define EXIT_STATUS_0(st)  ((st) == 0)
@@ -4858,6 +4863,29 @@ retry:
 }
 #endif							/* WIN32 */
 
+/*
+ * shmemSetup
+ *
+ * Helper function for a child to set up shmem before
+ * executing.
+ *
+ * aux_process - set to true if an auxiliary process.
+ */
+static void
+shmemSetup(bool aux_process)
+{
+	/* Restore basic shared memory pointers */
+	InitShmemAccess(UsedShmemSegAddr);
+
+	/* Need a PGPROC to run CreateSharedMemoryAndSemaphores */
+	if (aux_process)
+		InitAuxiliaryProcess();
+	else
+		InitProcess();
+
+	/* Attach process to shared data structures */
+	CreateSharedMemoryAndSemaphores();
+}
 
 /*
  * SubPostmasterMain -- Get the fork/exec'd process into a state equivalent
@@ -4943,9 +4971,9 @@ SubPostmasterMain(int argc, char *argv[])
 
 	/* autovacuum needs this set before calling InitProcess */
 	if (strcmp(argv[1], "--forkavlauncher") == 0)
-		AutovacuumLauncherIAm();
+		am_autovacuum_launcher = true;
 	if (strcmp(argv[1], "--forkavworker") == 0)
-		AutovacuumWorkerIAm();
+		am_autovacuum_worker = true;
 
 	/*
 	 * Start our win32 signal implementation. This has to be done after we
@@ -5038,41 +5066,17 @@ SubPostmasterMain(int argc, char *argv[])
 	}
 	if (strcmp(argv[1], "--forkboot") == 0)
 	{
-		/* Restore basic shared memory pointers */
-		InitShmemAccess(UsedShmemSegAddr);
-
-		/* Need a PGPROC to run CreateSharedMemoryAndSemaphores */
-		InitAuxiliaryProcess();
-
-		/* Attach process to shared data structures */
-		CreateSharedMemoryAndSemaphores();
-
+		shmemSetup(true);
 		AuxiliaryProcessMain(argc - 2, argv + 2);	/* does not return */
 	}
 	if (strcmp(argv[1], "--forkavlauncher") == 0)
 	{
-		/* Restore basic shared memory pointers */
-		InitShmemAccess(UsedShmemSegAddr);
-
-		/* Need a PGPROC to run CreateSharedMemoryAndSemaphores */
-		InitProcess();
-
-		/* Attach process to shared data structures */
-		CreateSharedMemoryAndSemaphores();
-
+		shmemSetup(true);
 		AutoVacLauncherMain(argc - 2, argv + 2);	/* does not return */
 	}
 	if (strcmp(argv[1], "--forkavworker") == 0)
 	{
-		/* Restore basic shared memory pointers */
-		InitShmemAccess(UsedShmemSegAddr);
-
-		/* Need a PGPROC to run CreateSharedMemoryAndSemaphores */
-		InitProcess();
-
-		/* Attach process to shared data structures */
-		CreateSharedMemoryAndSemaphores();
-
+		shmemSetup(true);
 		AutoVacWorkerMain(argc - 2, argv + 2);	/* does not return */
 	}
 	if (strncmp(argv[1], "--forkbgworker=", 15) == 0)
@@ -5450,6 +5454,11 @@ StartChildProcess(ForkProcType type)
 		case WalReceiverFork:
 			PrepAuxProcessFork(fork_data);
 			break;
+		/* Non-Auxiliary Processes */
+		case AutoVacLauncherFork:
+		case AutoVacWorkerFork:
+			PrepAutoVacProcessFork(fork_data);
+			break;
 
 		default:
 			break;
diff --git a/src/include/postmaster/autovacuum.h b/src/include/postmaster/autovacuum.h
index 8451e5d9e2..518775f528 100644
--- a/src/include/postmaster/autovacuum.h
+++ b/src/include/postmaster/autovacuum.h
@@ -15,6 +15,7 @@
 #define AUTOVACUUM_H
 
 #include "storage/block.h"
+#include "postmaster/fork_process.h"
 
 /*
  * Other processes can request specific work from autovacuum, identified by
@@ -45,6 +46,10 @@ extern int	AutovacuumLauncherPid;
 
 extern int	Log_autovacuum_min_duration;
 
+/* autovacuum identification */
+extern bool am_autovacuum_launcher;
+extern bool am_autovacuum_worker;
+
 /* Status inquiry functions */
 extern bool AutoVacuumingActive(void);
 extern bool IsAutoVacuumLauncherProcess(void);
@@ -58,6 +63,8 @@ extern void autovac_init(void);
 extern int	StartAutoVacLauncher(void);
 extern int	StartAutoVacWorker(void);
 
+extern void PrepAutoVacProcessFork(ForkProcData *autovac_fork);
+
 /* called from postmaster when a worker could not be forked */
 extern void AutoVacWorkerFailed(void);
 
@@ -67,8 +74,6 @@ extern void AutoVacuumUpdateDelay(void);
 #ifdef EXEC_BACKEND
 extern void AutoVacLauncherMain(int argc, char *argv[]) pg_attribute_noreturn();
 extern void AutoVacWorkerMain(int argc, char *argv[]) pg_attribute_noreturn();
-extern void AutovacuumWorkerIAm(void);
-extern void AutovacuumLauncherIAm(void);
 #endif
 
 extern bool AutoVacuumRequestWork(AutoVacuumWorkItemType type,
diff --git a/src/include/postmaster/fork_process.h b/src/include/postmaster/fork_process.h
index d912229055..1f319fc98f 100644
--- a/src/include/postmaster/fork_process.h
+++ b/src/include/postmaster/fork_process.h
@@ -24,6 +24,8 @@ typedef enum
    CheckpointerFork,
    WalWriterFork,
    WalReceiverFork,	/* end of Auxiliary Process Forks */
+   AutoVacLauncherFork,
+   AutoVacWorkerFork,
 
    NUMFORKPROCTYPES			/* Must be last! */
 } ForkProcType;
-- 
2.23.0

