Improve various places that double the size of a buffer
authorDavid Rowley <[email protected]>
Thu, 1 Jul 2021 03:29:06 +0000 (15:29 +1200)
committerDavid Rowley <[email protected]>
Thu, 1 Jul 2021 03:29:06 +0000 (15:29 +1200)
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 the 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.

Discussion: https://postgr.es/m/CAApHDvp=tns7RL4PH0ZR0M+M-YFLquK7218x=0B_zO+DbOma+w@mail.gmail.com
Reviewed-by: Zhihong Yu
src/backend/parser/scan.l
src/backend/storage/ipc/shm_mq.c
src/backend/storage/lmgr/lwlock.c
src/backend/tsearch/spell.c
src/backend/tsearch/ts_parse.c
src/backend/utils/cache/inval.c
src/backend/utils/cache/typcache.c

index 9f9d8a17061d1c811f89f27fddcd7c009b00fcfb..6e6824faebd28ad995c42466e52385741befd2ac 100644 (file)
@@ -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);
    }
index 8a46962f939a35a0e2e26aaba939b085b3b95f9f..446f20df4617e36a72c243a8092c2736c8c87f35 100644 (file)
@@ -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)
index 55b9d7970ec387a1f6cb693c8f885e48757bbb4c..ffb6fa36cc508aa9d1552c236896cfe2802ee5c9 100644 (file)
@@ -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,
index ebc89604ac2071e333400b01516aacddae413764..934be3d7d33c711efbaaa8dbc8383b65a36330f9 100644 (file)
@@ -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,
index 92d95b4bd49714f4eb36f56d710c45b121ec7036..d978c8850de9889115fcef66a28acb31309964a5 100644 (file)
@@ -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));
index dcfd9e83893e9b047dca6b4525b1d7c24870404d..d22cc5a93b38f1a65157fafc9e40857d12f7e0e1 100644 (file)
 #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
index de96e96c8fdd1301dcc4557406baa0f86e912e9b..976bd9e61aac1a44d90e45211e1ace9f80c360e8 100644 (file)
@@ -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));