v1-0001-Speed-up-creation-of-command-completion-tags.patch

text/plain

Filename: v1-0001-Speed-up-creation-of-command-completion-tags.patch
Type: text/plain
Part: 0
Message: Speedup generation of command completion tags

Patch

Format: format-patch
Series: patch v1-0001
Subject: Speed up creation of command completion tags
File+
src/backend/tcop/cmdtag.c 9 1
src/backend/tcop/dest.c 47 25
src/include/tcop/cmdtag.h 1 0
From 5900b1662aea3d82c4aad1f8a94d9f9242067e9c Mon Sep 17 00:00:00 2001
From: David Rowley <dgrowley@gmail.com>
Date: Sat, 10 Dec 2022 20:27:01 +1300
Subject: [PATCH v1] Speed up creation of command completion tags

Author: David Rowley, Andres Freund
---
 src/backend/tcop/cmdtag.c | 10 +++++-
 src/backend/tcop/dest.c   | 72 +++++++++++++++++++++++++--------------
 src/include/tcop/cmdtag.h |  1 +
 3 files changed, 57 insertions(+), 26 deletions(-)

diff --git a/src/backend/tcop/cmdtag.c b/src/backend/tcop/cmdtag.c
index 262484f561..36f7c37ec4 100644
--- a/src/backend/tcop/cmdtag.c
+++ b/src/backend/tcop/cmdtag.c
@@ -20,13 +20,14 @@
 typedef struct CommandTagBehavior
 {
 	const char *name;
+	const uint8 namelen;
 	const bool	event_trigger_ok;
 	const bool	table_rewrite_ok;
 	const bool	display_rowcount;
 } CommandTagBehavior;
 
 #define PG_CMDTAG(tag, name, evtrgok, rwrok, rowcnt) \
-	{ name, evtrgok, rwrok, rowcnt },
+	{ name, (uint8) (sizeof(name) - 1), evtrgok, rwrok, rowcnt },
 
 static const CommandTagBehavior tag_behavior[COMMAND_TAG_NEXTTAG] = {
 #include "tcop/cmdtaglist.h"
@@ -47,6 +48,13 @@ GetCommandTagName(CommandTag commandTag)
 	return tag_behavior[commandTag].name;
 }
 
+const char *
+GetCommandTagNameAndLen(CommandTag commandTag, Size *len)
+{
+	*len = (Size) tag_behavior[commandTag].namelen;
+	return tag_behavior[commandTag].name;
+}
+
 bool
 command_tag_display_rowcount(CommandTag commandTag)
 {
diff --git a/src/backend/tcop/dest.c b/src/backend/tcop/dest.c
index 6afaa153ca..e80a501dce 100644
--- a/src/backend/tcop/dest.c
+++ b/src/backend/tcop/dest.c
@@ -39,6 +39,7 @@
 #include "executor/tstoreReceiver.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
+#include "utils/builtins.h"
 #include "utils/portal.h"
 
 
@@ -158,6 +159,49 @@ CreateDestReceiver(CommandDest dest)
 	pg_unreachable();
 }
 
+static inline Size
+make_completion_tag(char *buff, const QueryCompletion *qc,
+					bool force_undecorated_output)
+{
+	CommandTag	tag = qc->commandTag;
+	Size		taglen;
+	const char *tagname = GetCommandTagNameAndLen(tag, &taglen);
+	char	   *bufp;
+
+	/*
+	 * We assume the tagname is plain ASCII and therefore requires no encoding
+	 * conversion.
+	 */
+	memcpy(buff, tagname, taglen + 1);
+	bufp = buff + taglen;
+
+	/* ensure that the tagname isn't long enough to overrun the buffer */
+	Assert(taglen <= COMPLETION_TAG_BUFSIZE - MAXINT8LEN - 4);
+
+	/*
+	 * In PostgreSQL versions 11 and earlier, it was possible to create a
+	 * table WITH OIDS.  When inserting into such a table, INSERT used to
+	 * include the Oid of the inserted record in the completion tag.  To
+	 * maintain compatibility in the wire protocol, we now write a "0" (for
+	 * InvalidOid) in the location where we once wrote the new record's Oid.
+	 */
+	if (command_tag_display_rowcount(tag) && !force_undecorated_output)
+	{
+		if (tag == CMDTAG_INSERT)
+		{
+			*bufp++ = ' ';
+			*bufp++ = '0';
+		}
+		*bufp++ = ' ';
+		bufp += pg_ulltoa_n(qc->nprocessed, bufp);
+		*bufp = '\0';
+	}
+
+	Assert((bufp - buff) == strlen(buff));
+
+	return bufp - buff;
+}
+
 /* ----------------
  *		EndCommand - clean up the destination at end of command
  * ----------------
@@ -166,8 +210,7 @@ void
 EndCommand(const QueryCompletion *qc, CommandDest dest, bool force_undecorated_output)
 {
 	char		completionTag[COMPLETION_TAG_BUFSIZE];
-	CommandTag	tag;
-	const char *tagname;
+	Size		len;
 
 	switch (dest)
 	{
@@ -175,29 +218,8 @@ EndCommand(const QueryCompletion *qc, CommandDest dest, bool force_undecorated_o
 		case DestRemoteExecute:
 		case DestRemoteSimple:
 
-			/*
-			 * We assume the tagname is plain ASCII and therefore requires no
-			 * encoding conversion.
-			 */
-			tag = qc->commandTag;
-			tagname = GetCommandTagName(tag);
-
-			/*
-			 * In PostgreSQL versions 11 and earlier, it was possible to
-			 * create a table WITH OIDS.  When inserting into such a table,
-			 * INSERT used to include the Oid of the inserted record in the
-			 * completion tag.  To maintain compatibility in the wire
-			 * protocol, we now write a "0" (for InvalidOid) in the location
-			 * where we once wrote the new record's Oid.
-			 */
-			if (command_tag_display_rowcount(tag) && !force_undecorated_output)
-				snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
-						 tag == CMDTAG_INSERT ?
-						 "%s 0 " UINT64_FORMAT : "%s " UINT64_FORMAT,
-						 tagname, qc->nprocessed);
-			else
-				snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s", tagname);
-			pq_putmessage('C', completionTag, strlen(completionTag) + 1);
+			len = make_completion_tag(completionTag, qc, force_undecorated_output);
+			pq_putmessage('C', completionTag, len + 1);
 
 		case DestNone:
 		case DestDebug:
diff --git a/src/include/tcop/cmdtag.h b/src/include/tcop/cmdtag.h
index 60e3179c74..ca1008db25 100644
--- a/src/include/tcop/cmdtag.h
+++ b/src/include/tcop/cmdtag.h
@@ -50,6 +50,7 @@ CopyQueryCompletion(QueryCompletion *dst, const QueryCompletion *src)
 
 extern void InitializeQueryCompletion(QueryCompletion *qc);
 extern const char *GetCommandTagName(CommandTag commandTag);
+extern const char *GetCommandTagNameAndLen(CommandTag commandTag, Size *len);
 extern bool command_tag_display_rowcount(CommandTag commandTag);
 extern bool command_tag_event_trigger_ok(CommandTag commandTag);
 extern bool command_tag_table_rewrite_ok(CommandTag commandTag);
-- 
2.35.1.windows.2