From 85cac3f12ff70df613859d01dca8d971701442f6 Mon Sep 17 00:00:00 2001
From: Mike Palmiotto <mike.palmiotto@crunchydata.com>
Date: Fri, 27 Sep 2019 20:34:17 -0400
Subject: [PATCH 5/8] Add syslogger to process centralization

---
 src/backend/postmaster/postmaster.c   |  17 ++-
 src/backend/postmaster/syslogger.c    | 152 ++++++++++----------------
 src/include/postmaster/fork_process.h |   1 +
 src/include/postmaster/syslogger.h    |   3 +
 4 files changed, 79 insertions(+), 94 deletions(-)

diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 6bdd57d1e2..5d78db067f 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -551,6 +551,7 @@ static void ShmemBackendArrayRemove(Backend *bn);
 #define StartAutoVacWorker()		StartChildProcess(AutoVacWorkerFork)
 #define pgstat_start()			StartChildProcess(PgstatCollectorFork)
 #define pgarch_start()			StartChildProcess(PgArchiverFork)
+#define SysLogger_Start()		StartChildProcess(SysLoggerFork)
 
 /* Macros to check exit status of a child process */
 #define EXIT_STATUS_0(st)  ((st) == 0)
@@ -5467,6 +5468,12 @@ StartChildProcess(ForkProcType type)
 		case PgArchiverFork:
 			PrepPgArchiverFork(fork_data);
 			break;
+		case SysLoggerFork:
+			if (!Logging_collector)
+				return 0;
+
+			PrepSysLoggerFork(fork_data);
+			break;
 		default:
 			break;
 	}
@@ -5488,13 +5495,21 @@ StartChildProcess(ForkProcType type)
 #ifndef EXEC_BACKEND
 		InitPostmasterChild();
 
+		/* Release postmaster's working memory context */
+		if (type != SysLoggerFork)
+		{
 		/* Close the postmaster's sockets */
 		ClosePostmasterPorts(false);
 
-		/* Release postmaster's working memory context */
 		MemoryContextSwitchTo(TopMemoryContext);
 		MemoryContextDelete(PostmasterContext);
+
 		PostmasterContext = NULL;
+		}
+		else
+		{
+			ClosePostmasterPorts(true);
+		}
 #endif
 		/* Call the process's main subroutine */
 		fork_data->child_main (fork_data->ac, fork_data->av);
diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c
index bb2baff763..37baad6450 100644
--- a/src/backend/postmaster/syslogger.c
+++ b/src/backend/postmaster/syslogger.c
@@ -48,6 +48,7 @@
 #include "storage/pg_shmem.h"
 #include "tcop/tcopprot.h"
 #include "utils/guc.h"
+#include "utils/memutils.h"
 #include "utils/ps_status.h"
 #include "utils/timestamp.h"
 
@@ -134,10 +135,12 @@ static volatile sig_atomic_t rotation_requested = false;
 
 /* Local subroutines */
 #ifdef EXEC_BACKEND
-static pid_t syslogger_forkexec(void);
 static void syslogger_parseArgs(int argc, char *argv[]);
 #endif
+
 NON_EXEC_STATIC void SysLoggerMain(int argc, char *argv[]) pg_attribute_noreturn();
+NON_EXEC_STATIC void SysLoggerPostmasterMain(int argc, char *argv[]);
+
 static void process_pipe_input(char *logbuffer, int *bytes_in_logbuffer);
 static void flush_pipe_input(char *logbuffer, int *bytes_in_logbuffer);
 static FILE *logfile_open(const char *filename, const char *mode,
@@ -171,12 +174,16 @@ SysLoggerMain(int argc, char *argv[])
 	pg_time_t	now;
 	WaitEventSet *wes;
 
-	now = MyStartTime;
-
 #ifdef EXEC_BACKEND
 	syslogger_parseArgs(argc, argv);
+#else
+	/* Drop our connection to postmaster's shared memory, as well */
+	dsm_detach_all();
+	PGSharedMemoryDetach();
 #endif							/* EXEC_BACKEND */
 
+	now = MyStartTime;
+
 	am_syslogger = true;
 
 	init_ps_display("logger", "", "", "");
@@ -540,16 +547,42 @@ SysLoggerMain(int argc, char *argv[])
 }
 
 /*
- * Postmaster subroutine to start a syslogger subprocess.
+ * Helper function for setting up a file number buffer
+ */
+static char *
+setup_file_buff(FILE *file)
+{
+	char	*filenobuf;
+
+	/* static variables (those not passed by write_backend_variables) */
+#ifndef WIN32
+	if (file != NULL)
+		filenobuf = psprintf("%d", fileno(file));
+	else
+		filenobuf = pstrdup("-1");
+#else							/* WIN32 */
+	if (file != NULL)
+		filenobuf = psprintf("%ld", (long) _get_osfhandle(_fileno(file)));
+	else
+		filenobuf = pstrdup("0");
+#endif							/* WIN32 */
+
+	return filenobuf;
+}
+
+/*
+ * PrepSysLoggerFork
+ *
+ * Postmaster subroutine to prepare a syslogger subprocess.
  */
-int
-SysLogger_Start(void)
+void
+PrepSysLoggerFork(ForkProcData *logger_fork)
 {
-	pid_t		sysloggerPid;
+	int				ac = 0;
 	char	   *filename;
+	MemoryContext	cxt;
 
-	if (!Logging_collector)
-		return 0;
+	cxt = MemoryContextSwitchTo(PostmasterContext);
 
 	/*
 	 * If first time through, create the pipe which will receive stderr
@@ -626,37 +659,29 @@ SysLogger_Start(void)
 		pfree(filename);
 	}
 
-#ifdef EXEC_BACKEND
-	switch ((sysloggerPid = syslogger_forkexec()))
-#else
-	switch ((sysloggerPid = fork_process()))
-#endif
-	{
-		case -1:
-			ereport(LOG,
-					(errmsg("could not fork system logger: %m")));
-			return 0;
+	MemoryContextSwitchTo(cxt);
 
-#ifndef EXEC_BACKEND
-		case 0:
-			/* in postmaster child ... */
-			InitPostmasterChild();
+	logger_fork->av[ac++] = pstrdup("postgres");
+	logger_fork->av[ac++] = pstrdup("--forklog");
+	logger_fork->av[ac++] = NULL;			/* filled in by postmaster_forkexec */
 
-			/* Close the postmaster's sockets */
-			ClosePostmasterPorts(true);
+	logger_fork->av[ac++] = setup_file_buff(syslogFile);
+	logger_fork->av[ac++] = setup_file_buff(csvlogFile);
 
-			/* Drop our connection to postmaster's shared memory, as well */
-			dsm_detach_all();
-			PGSharedMemoryDetach();
+	logger_fork->av[ac] = NULL;
 
-			/* do the work */
-			SysLoggerMain(0, NULL);
-			break;
-#endif
+	logger_fork->ac = ac;
+	Assert(logger_fork->ac < lengthof(*logger_fork->av));
+
+	logger_fork->child_main = SysLoggerMain;
+	logger_fork->postmaster_main = SysLoggerPostmasterMain;
+	logger_fork->type_desc = pstrdup("system logger");
+}
 
-		default:
-			/* success, in postmaster */
 
+NON_EXEC_STATIC void
+SysLoggerPostmasterMain(int argc, char *argv[])
+{
 			/* now we redirect stderr, if not done already */
 			if (!redirection_done)
 			{
@@ -723,70 +748,11 @@ SysLogger_Start(void)
 				fclose(csvlogFile);
 				csvlogFile = NULL;
 			}
-			return (int) sysloggerPid;
-	}
-
-	/* we should never reach here */
-	return 0;
 }
 
 
 #ifdef EXEC_BACKEND
 
-/*
- * syslogger_forkexec() -
- *
- * Format up the arglist for, then fork and exec, a syslogger process
- */
-static pid_t
-syslogger_forkexec(void)
-{
-	char	   *av[10];
-	int			ac = 0;
-	char		filenobuf[32];
-	char		csvfilenobuf[32];
-
-	av[ac++] = "postgres";
-	av[ac++] = "--forklog";
-	av[ac++] = NULL;			/* filled in by postmaster_forkexec */
-
-	/* static variables (those not passed by write_backend_variables) */
-#ifndef WIN32
-	if (syslogFile != NULL)
-		snprintf(filenobuf, sizeof(filenobuf), "%d",
-				 fileno(syslogFile));
-	else
-		strcpy(filenobuf, "-1");
-#else							/* WIN32 */
-	if (syslogFile != NULL)
-		snprintf(filenobuf, sizeof(filenobuf), "%ld",
-				 (long) _get_osfhandle(_fileno(syslogFile)));
-	else
-		strcpy(filenobuf, "0");
-#endif							/* WIN32 */
-	av[ac++] = filenobuf;
-
-#ifndef WIN32
-	if (csvlogFile != NULL)
-		snprintf(csvfilenobuf, sizeof(csvfilenobuf), "%d",
-				 fileno(csvlogFile));
-	else
-		strcpy(csvfilenobuf, "-1");
-#else							/* WIN32 */
-	if (csvlogFile != NULL)
-		snprintf(csvfilenobuf, sizeof(csvfilenobuf), "%ld",
-				 (long) _get_osfhandle(_fileno(csvlogFile)));
-	else
-		strcpy(csvfilenobuf, "0");
-#endif							/* WIN32 */
-	av[ac++] = csvfilenobuf;
-
-	av[ac] = NULL;
-	Assert(ac < lengthof(av));
-
-	return postmaster_forkexec(ac, av);
-}
-
 /*
  * syslogger_parseArgs() -
  *
diff --git a/src/include/postmaster/fork_process.h b/src/include/postmaster/fork_process.h
index 86bad60cea..32e10e3629 100644
--- a/src/include/postmaster/fork_process.h
+++ b/src/include/postmaster/fork_process.h
@@ -28,6 +28,7 @@ typedef enum
    AutoVacWorkerFork,
    PgstatCollectorFork,
    PgArchiverFork,
+   SysLoggerFork,
 
    NUMFORKPROCTYPES			/* Must be last! */
 } ForkProcType;
diff --git a/src/include/postmaster/syslogger.h b/src/include/postmaster/syslogger.h
index 3a61104573..1d0b125141 100644
--- a/src/include/postmaster/syslogger.h
+++ b/src/include/postmaster/syslogger.h
@@ -14,6 +14,7 @@
 
 #include <limits.h>				/* for PIPE_BUF */
 
+#include "postmaster/fork_process.h"
 
 /*
  * Primitive protocol structure for writing to syslogger pipe(s).  The idea
@@ -83,6 +84,8 @@ extern int	SysLogger_Start(void);
 
 extern void write_syslogger_file(const char *buffer, int count, int dest);
 
+extern void PrepSysLoggerFork(ForkProcData *logger_fork);
+
 #ifdef EXEC_BACKEND
 extern void SysLoggerMain(int argc, char *argv[]) pg_attribute_noreturn();
 #endif
-- 
2.23.0

