From 3788c66788e9f8c6904c6fe903724c1f44812c4d Mon Sep 17 00:00:00 2001 From: David Rowley Date: Thu, 1 Jul 2021 15:29:06 +1200 Subject: [PATCH] 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 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 | 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 9f9d8a17061..6e6824faebd 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 8a46962f939..446f20df461 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 55b9d7970ec..ffb6fa36cc5 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 ebc89604ac2..934be3d7d33 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 92d95b4bd49..d978c8850de 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 dcfd9e83893..d22cc5a93b3 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 de96e96c8fd..976bd9e61aa 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));