From ad3fd72018fec9b180860c7d868de766ee7c1c4f Mon Sep 17 00:00:00 2001
From: Sehrope Sarkuni <sehrope@jackdb.com>
Date: Wed, 10 Jul 2019 09:29:15 -0400
Subject: [PATCH 2/2] Use log destination bitmap in log pipe protocol

Replaces the dest field in PipeProtoHeader with dest_last, a
bitmap of the log destination and whether the message is the
last chunk of a message.
---
 src/backend/postmaster/syslogger.c | 12 +++++-------
 src/backend/utils/error/elog.c     |  4 ++--
 src/include/postmaster/syslogger.h |  5 +++--
 src/include/utils/elog.h           |  5 ++++-
 4 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c
index bafd31d22b..f8a8cee401 100644
--- a/src/backend/postmaster/syslogger.c
+++ b/src/backend/postmaster/syslogger.c
@@ -879,21 +879,22 @@ process_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
 {
 	char	   *cursor = logbuffer;
 	int			count = *bytes_in_logbuffer;
-	int			dest = LOG_DESTINATION_STDERR;
 
 	/* While we have enough for a header, process data... */
 	while (count >= (int) (offsetof(PipeProtoHeader, data) + 1))
 	{
 		PipeProtoHeader p;
 		int			chunklen;
+		int 		dest;
 
 		/* Do we have a valid header? */
 		memcpy(&p, cursor, offsetof(PipeProtoHeader, data));
+		dest = p.dest_last & ~PIPE_MESSAGE_IS_LAST;
 		if (p.nuls[0] == '\0' && p.nuls[1] == '\0' &&
 			p.len > 0 && p.len <= PIPE_MAX_PAYLOAD &&
 			p.pid != 0 &&
-			(p.is_last == 't' || p.is_last == 'f' ||
-			 p.is_last == 'T' || p.is_last == 'F'))
+			(dest == LOG_DESTINATION_CSVLOG ||
+			 dest == LOG_DESTINATION_STDERR))
 		{
 			List	   *buffer_list;
 			ListCell   *cell;
@@ -907,9 +908,6 @@ process_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
 			if (count < chunklen)
 				break;
 
-			dest = (p.is_last == 'T' || p.is_last == 'F') ?
-				LOG_DESTINATION_CSVLOG : LOG_DESTINATION_STDERR;
-
 			/* Locate any existing buffer for this source pid */
 			buffer_list = buffer_lists[p.pid % NBUFFER_LISTS];
 			foreach(cell, buffer_list)
@@ -925,7 +923,7 @@ process_pipe_input(char *logbuffer, int *bytes_in_logbuffer)
 					free_slot = buf;
 			}
 
-			if (p.is_last == 'f' || p.is_last == 'F')
+			if (!(p.dest_last & PIPE_MESSAGE_IS_LAST))
 			{
 				/*
 				 * Save a complete non-final chunk in a per-pid buffer
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 8b4720ef3a..e69fb6b87c 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -3089,7 +3089,7 @@ write_pipe_chunks(char *data, int len, int dest)
 	/* write all but the last chunk */
 	while (len > PIPE_MAX_PAYLOAD)
 	{
-		p.proto.is_last = (dest == LOG_DESTINATION_CSVLOG ? 'F' : 'f');
+		p.proto.dest_last = (unsigned char) dest;
 		p.proto.len = PIPE_MAX_PAYLOAD;
 		memcpy(p.proto.data, data, PIPE_MAX_PAYLOAD);
 		rc = write(fd, &p, PIPE_HEADER_SIZE + PIPE_MAX_PAYLOAD);
@@ -3099,7 +3099,7 @@ write_pipe_chunks(char *data, int len, int dest)
 	}
 
 	/* write the last chunk */
-	p.proto.is_last = (dest == LOG_DESTINATION_CSVLOG ? 'T' : 't');
+	p.proto.dest_last = (unsigned char) (dest | PIPE_MESSAGE_IS_LAST);
 	p.proto.len = len;
 	memcpy(p.proto.data, data, len);
 	rc = write(fd, &p, PIPE_HEADER_SIZE + len);
diff --git a/src/include/postmaster/syslogger.h b/src/include/postmaster/syslogger.h
index 3a61104573..3b95700cdb 100644
--- a/src/include/postmaster/syslogger.h
+++ b/src/include/postmaster/syslogger.h
@@ -46,8 +46,8 @@ typedef struct
 	char		nuls[2];		/* always \0\0 */
 	uint16		len;			/* size of this chunk (counts data only) */
 	int32		pid;			/* writer's pid */
-	char		is_last;		/* last chunk of message? 't' or 'f' ('T' or
-								 * 'F' for CSV case) */
+	unsigned char		dest_last;	/* bitmap for log destination and whether
+									 * this is the last chunk of message */
 	char		data[FLEXIBLE_ARRAY_MEMBER];	/* data payload starts here */
 } PipeProtoHeader;
 
@@ -60,6 +60,7 @@ typedef union
 #define PIPE_HEADER_SIZE  offsetof(PipeProtoHeader, data)
 #define PIPE_MAX_PAYLOAD  ((int) (PIPE_CHUNK_SIZE - PIPE_HEADER_SIZE))
 
+#define PIPE_MESSAGE_IS_LAST	(1<<7)
 
 /* GUC options */
 extern bool Logging_collector;
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index dbfd8efd26..c9f33c8a5f 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -408,7 +408,10 @@ extern char *Log_destination_string;
 extern bool syslog_sequence_numbers;
 extern bool syslog_split_messages;
 
-/* Log destination bitmap */
+/*
+ * Log destination bitmap
+ * Max value is 1<<6 as PipeProtoHeader.dest_last uses the last bit as a flag.
+ */
 #define LOG_DESTINATION_STDERR	 1
 #define LOG_DESTINATION_SYSLOG	 2
 #define LOG_DESTINATION_EVENTLOG 4
-- 
2.17.1

