v1-0001-Improve-various-places-that-double-the-size-of-a-.patch

application/octet-stream

Filename: v1-0001-Improve-various-places-that-double-the-size-of-a-.patch
Type: application/octet-stream
Part: 0
Message: Use pg_nextpower2_* in a few more places

Patch

Format: format-patch
Series: patch v1-0001
Subject: Improve various places that double the size of a buffer
File+
src/backend/parser/scan.l 2 4
src/backend/storage/ipc/shm_mq.c 9 5
src/backend/storage/lmgr/lwlock.c 3 7
src/backend/tsearch/spell.c 2 1
src/backend/tsearch/ts_parse.c 1 1
src/backend/utils/cache/inval.c 2 2
src/backend/utils/cache/typcache.c 2 4
From ae1a3a874e24ee71a00809e347029fc9e7a6b0c9 Mon Sep 17 00:00:00 2001
From: "dgrowley@gmail.com" <dgrowley@gmail.com>
Date: Mon, 12 Apr 2021 22:04:53 +1200
Subject: [PATCH v1] Improve various places that double the size of a buffer

Several places were performing a tight loop to determine the first power
of 2 number that's > or >= the required memory.  Instead of using a loop
for that, we can use pg_nextpower2_32 or pg_nextpower2_64.  When we need a
power of 2 number equal to or greater than a given amount, we just pass
the amount to the nextpower2 function.  When we need a power of 2 greater
than the amount, we just pass amount + 1.

Additionally, in tsearch there were a couple of locations that were
performing a while loop when a simple "if" would have done.  In both of
these locations only 1 item is being added, so the loop could only have
ever iterated once.  Changing the loop into an if statement makes the code
very slightly more optimal as the condition is checked once rather than
twice.

There are quite a few remaining locations that increase the size of the
buffer in the following form:

  while (reqsize >= buflen)
  {
     buflen *= 2;
     buf = repalloc(buf, buflen);
  }

These are not touched in this commit.  repalloc will error out for sizes
larger than MaxAllocSize.  Changing these to use pg_nextpower2_32 would
remove the chance of that error being raised.  It's unclear from the code
if the sizes could ever become that large, so err on the side of caution.
---
 src/backend/parser/scan.l          |  6 ++----
 src/backend/storage/ipc/shm_mq.c   | 14 +++++++++-----
 src/backend/storage/lmgr/lwlock.c  | 10 +++-------
 src/backend/tsearch/spell.c        |  3 ++-
 src/backend/tsearch/ts_parse.c     |  2 +-
 src/backend/utils/cache/inval.c    |  4 ++--
 src/backend/utils/cache/typcache.c |  6 ++----
 7 files changed, 21 insertions(+), 24 deletions(-)

diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l
index 9f9d8a1706..6e6824faeb 100644
--- a/src/backend/parser/scan.l
+++ b/src/backend/parser/scan.l
@@ -39,6 +39,7 @@
 #include "parser/gramparse.h"
 #include "parser/parser.h"		/* only needed for GUC variables */
 #include "parser/scansup.h"
+#include "port/pg_bitutils.h"
 #include "mb/pg_wchar.h"
 }
 
@@ -1253,10 +1254,7 @@ addlit(char *ytext, int yleng, core_yyscan_t yyscanner)
 	/* enlarge buffer if needed */
 	if ((yyextra->literallen + yleng) >= yyextra->literalalloc)
 	{
-		do
-		{
-			yyextra->literalalloc *= 2;
-		} while ((yyextra->literallen + yleng) >= yyextra->literalalloc);
+		yyextra->literalalloc = pg_nextpower2_32(yyextra->literallen + yleng + 1);
 		yyextra->literalbuf = (char *) repalloc(yyextra->literalbuf,
 												yyextra->literalalloc);
 	}
diff --git a/src/backend/storage/ipc/shm_mq.c b/src/backend/storage/ipc/shm_mq.c
index 8a46962f93..446f20df46 100644
--- a/src/backend/storage/ipc/shm_mq.c
+++ b/src/backend/storage/ipc/shm_mq.c
@@ -20,6 +20,7 @@
 
 #include "miscadmin.h"
 #include "pgstat.h"
+#include "port/pg_bitutils.h"
 #include "postmaster/bgworker.h"
 #include "storage/procsignal.h"
 #include "storage/shm_mq.h"
@@ -720,14 +721,17 @@ shm_mq_receive(shm_mq_handle *mqh, Size *nbytesp, void **datap, bool nowait)
 		 */
 		if (mqh->mqh_buflen < nbytes)
 		{
-			Size		newbuflen = Max(mqh->mqh_buflen, MQH_INITIAL_BUFSIZE);
+			Size		newbuflen;
 
 			/*
-			 * Double the buffer size until the payload fits, but limit to
-			 * MaxAllocSize.
+			 * Increase size to the next power of 2 that's >= nbytes, but
+			 * limit to MaxAllocSize.
 			 */
-			while (newbuflen < nbytes)
-				newbuflen *= 2;
+#if SIZEOF_SIZE_T == 4
+			newbuflen = pg_nextpower2_32(nbytes);
+#else
+			newbuflen = pg_nextpower2_64(nbytes);
+#endif
 			newbuflen = Min(newbuflen, MaxAllocSize);
 
 			if (mqh->mqh_buffer != NULL)
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index 55b9d7970e..ffb6fa36cc 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -79,6 +79,7 @@
 #include "miscadmin.h"
 #include "pg_trace.h"
 #include "pgstat.h"
+#include "port/pg_bitutils.h"
 #include "postmaster/postmaster.h"
 #include "replication/slot.h"
 #include "storage/ipc.h"
@@ -659,9 +660,7 @@ LWLockRegisterTranche(int tranche_id, const char *tranche_name)
 	{
 		int			newalloc;
 
-		newalloc = Max(LWLockTrancheNamesAllocated, 8);
-		while (newalloc <= tranche_id)
-			newalloc *= 2;
+		newalloc = pg_nextpower2_32(Max(8, tranche_id + 1));
 
 		if (LWLockTrancheNames == NULL)
 			LWLockTrancheNames = (const char **)
@@ -715,10 +714,7 @@ RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
 
 	if (NamedLWLockTrancheRequests >= NamedLWLockTrancheRequestsAllocated)
 	{
-		int			i = NamedLWLockTrancheRequestsAllocated;
-
-		while (i <= NamedLWLockTrancheRequests)
-			i *= 2;
+		int			i = pg_nextpower2_32(NamedLWLockTrancheRequests + 1);
 
 		NamedLWLockTrancheRequestArray = (NamedLWLockTrancheRequest *)
 			repalloc(NamedLWLockTrancheRequestArray,
diff --git a/src/backend/tsearch/spell.c b/src/backend/tsearch/spell.c
index ebc89604ac..934be3d7d3 100644
--- a/src/backend/tsearch/spell.c
+++ b/src/backend/tsearch/spell.c
@@ -1600,7 +1600,8 @@ MergeAffix(IspellDict *Conf, int a1, int a2)
 	else if (*Conf->AffixData[a2] == '\0')
 		return a1;
 
-	while (Conf->nAffixData + 1 >= Conf->lenAffixData)
+	/* Double the size of AffixData if there's not enough space */
+	if (Conf->nAffixData + 1 >= Conf->lenAffixData)
 	{
 		Conf->lenAffixData *= 2;
 		Conf->AffixData = (char **) repalloc(Conf->AffixData,
diff --git a/src/backend/tsearch/ts_parse.c b/src/backend/tsearch/ts_parse.c
index 92d95b4bd4..d978c8850d 100644
--- a/src/backend/tsearch/ts_parse.c
+++ b/src/backend/tsearch/ts_parse.c
@@ -436,7 +436,7 @@ parsetext(Oid cfgId, ParsedText *prs, char *buf, int buflen)
 static void
 hladdword(HeadlineParsedText *prs, char *buf, int buflen, int type)
 {
-	while (prs->curwords >= prs->lenwords)
+	if (prs->curwords >= prs->lenwords)
 	{
 		prs->lenwords *= 2;
 		prs->words = (HeadlineWordEntry *) repalloc((void *) prs->words, prs->lenwords * sizeof(HeadlineWordEntry));
diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c
index dcfd9e8389..d22cc5a93b 100644
--- a/src/backend/utils/cache/inval.c
+++ b/src/backend/utils/cache/inval.c
@@ -106,6 +106,7 @@
 #include "catalog/catalog.h"
 #include "catalog/pg_constraint.h"
 #include "miscadmin.h"
+#include "port/pg_bitutils.h"
 #include "storage/sinval.h"
 #include "storage/smgr.h"
 #include "utils/catcache.h"
@@ -799,8 +800,7 @@ MakeSharedInvalidMessagesArray(const SharedInvalidationMessage *msgs, int n)
 
 	if ((numSharedInvalidMessagesArray + n) > maxSharedInvalidMessagesArray)
 	{
-		while ((numSharedInvalidMessagesArray + n) > maxSharedInvalidMessagesArray)
-			maxSharedInvalidMessagesArray *= 2;
+		maxSharedInvalidMessagesArray = pg_nextpower2_32(numSharedInvalidMessagesArray + n);
 
 		SharedInvalidMessagesArray = repalloc(SharedInvalidMessagesArray,
 											  maxSharedInvalidMessagesArray
diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c
index de96e96c8f..976bd9e61a 100644
--- a/src/backend/utils/cache/typcache.c
+++ b/src/backend/utils/cache/typcache.c
@@ -60,6 +60,7 @@
 #include "executor/executor.h"
 #include "lib/dshash.h"
 #include "optimizer/optimizer.h"
+#include "port/pg_bitutils.h"
 #include "storage/lwlock.h"
 #include "utils/builtins.h"
 #include "utils/catcache.h"
@@ -1708,10 +1709,7 @@ ensure_record_cache_typmod_slot_exists(int32 typmod)
 
 	if (typmod >= RecordCacheArrayLen)
 	{
-		int32		newlen = RecordCacheArrayLen * 2;
-
-		while (typmod >= newlen)
-			newlen *= 2;
+		int32		newlen = pg_nextpower2_32(typmod + 1);
 
 		RecordCacheArray = (TupleDesc *) repalloc(RecordCacheArray,
 												  newlen * sizeof(TupleDesc));
-- 
2.27.0