Skip to content

Commit d025cf8

Browse files
committed
Modify various power 2 calculations to use new helper functions
First pass of modifying various places that obtain the next power of 2 of a number and make them use the new functions added in pg_bitutils.h instead. This also removes the _hash_log2() function. There are no longer any callers in core. Other users can swap their _hash_log2(n) call to make use of pg_ceil_log2_32(n). Author: David Fetter, with some minor adjustments by me Reviewed-by: John Naylor, Jesse Zhang Discussion: https://postgr.es/m/20200114173553.GE32763%40fetter.org
1 parent 50a38f6 commit d025cf8

File tree

7 files changed

+32
-62
lines changed

7 files changed

+32
-62
lines changed

Diff for: src/backend/access/hash/hashpage.c

+11-13
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "access/hash.h"
3232
#include "access/hash_xlog.h"
3333
#include "miscadmin.h"
34+
#include "port/pg_bitutils.h"
3435
#include "storage/lmgr.h"
3536
#include "storage/predicate.h"
3637
#include "storage/smgr.h"
@@ -502,7 +503,7 @@ _hash_init_metabuffer(Buffer buf, double num_tuples, RegProcedure procid,
502503
double dnumbuckets;
503504
uint32 num_buckets;
504505
uint32 spare_index;
505-
uint32 i;
506+
uint32 lshift;
506507

507508
/*
508509
* Choose the number of initial bucket pages to match the fill factor
@@ -542,15 +543,12 @@ _hash_init_metabuffer(Buffer buf, double num_tuples, RegProcedure procid,
542543
metap->hashm_nmaps = 0;
543544
metap->hashm_ffactor = ffactor;
544545
metap->hashm_bsize = HashGetMaxBitmapSize(page);
546+
545547
/* find largest bitmap array size that will fit in page size */
546-
for (i = _hash_log2(metap->hashm_bsize); i > 0; --i)
547-
{
548-
if ((1 << i) <= metap->hashm_bsize)
549-
break;
550-
}
551-
Assert(i > 0);
552-
metap->hashm_bmsize = 1 << i;
553-
metap->hashm_bmshift = i + BYTE_TO_BIT;
548+
lshift = pg_leftmost_one_pos32(metap->hashm_bsize);
549+
Assert(lshift > 0);
550+
metap->hashm_bmsize = 1 << lshift;
551+
metap->hashm_bmshift = lshift + BYTE_TO_BIT;
554552
Assert((1 << BMPG_SHIFT(metap)) == (BMPG_MASK(metap) + 1));
555553

556554
/*
@@ -570,7 +568,7 @@ _hash_init_metabuffer(Buffer buf, double num_tuples, RegProcedure procid,
570568
* Set highmask as next immediate ((2 ^ x) - 1), which should be
571569
* sufficient to cover num_buckets.
572570
*/
573-
metap->hashm_highmask = (1 << (_hash_log2(num_buckets + 1))) - 1;
571+
metap->hashm_highmask = pg_nextpower2_32(num_buckets + 1) - 1;
574572
metap->hashm_lowmask = (metap->hashm_highmask >> 1);
575573

576574
MemSet(metap->hashm_spares, 0, sizeof(metap->hashm_spares));
@@ -659,9 +657,9 @@ _hash_expandtable(Relation rel, Buffer metabuf)
659657
*
660658
* Ideally we'd allow bucket numbers up to UINT_MAX-1 (no higher because
661659
* the calculation maxbucket+1 mustn't overflow). Currently we restrict
662-
* to half that because of overflow looping in _hash_log2() and
663-
* insufficient space in hashm_spares[]. It's moot anyway because an
664-
* index with 2^32 buckets would certainly overflow BlockNumber and hence
660+
* to half that to prevent failure of pg_ceil_log2_32() and insufficient
661+
* space in hashm_spares[]. It's moot anyway because an index with 2^32
662+
* buckets would certainly overflow BlockNumber and hence
665663
* _hash_alloc_buckets() would fail, but if we supported buckets smaller
666664
* than a disk block then this would be an independent constraint.
667665
*

Diff for: src/backend/access/hash/hashsort.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "commands/progress.h"
3030
#include "miscadmin.h"
3131
#include "pgstat.h"
32+
#include "port/pg_bitutils.h"
3233
#include "utils/tuplesort.h"
3334

3435

@@ -69,7 +70,7 @@ _h_spoolinit(Relation heap, Relation index, uint32 num_buckets)
6970
* NOTE : This hash mask calculation should be in sync with similar
7071
* calculation in _hash_init_metabuffer.
7172
*/
72-
hspool->high_mask = (((uint32) 1) << _hash_log2(num_buckets + 1)) - 1;
73+
hspool->high_mask = pg_nextpower2_32(num_buckets + 1) - 1;
7374
hspool->low_mask = (hspool->high_mask >> 1);
7475
hspool->max_buckets = num_buckets - 1;
7576

Diff for: src/backend/access/hash/hashutil.c

+2-17
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "access/hash.h"
1818
#include "access/reloptions.h"
1919
#include "access/relscan.h"
20+
#include "port/pg_bitutils.h"
2021
#include "storage/buf_internals.h"
2122
#include "utils/lsyscache.h"
2223
#include "utils/rel.h"
@@ -134,21 +135,6 @@ _hash_hashkey2bucket(uint32 hashkey, uint32 maxbucket,
134135
return bucket;
135136
}
136137

137-
/*
138-
* _hash_log2 -- returns ceil(lg2(num))
139-
*/
140-
uint32
141-
_hash_log2(uint32 num)
142-
{
143-
uint32 i,
144-
limit;
145-
146-
limit = 1;
147-
for (i = 0; limit < num; limit <<= 1, i++)
148-
;
149-
return i;
150-
}
151-
152138
/*
153139
* _hash_spareindex -- returns spare index / global splitpoint phase of the
154140
* bucket
@@ -158,8 +144,7 @@ _hash_spareindex(uint32 num_bucket)
158144
{
159145
uint32 splitpoint_group;
160146
uint32 splitpoint_phases;
161-
162-
splitpoint_group = _hash_log2(num_bucket);
147+
splitpoint_group = pg_ceil_log2_32(num_bucket);
163148

164149
if (splitpoint_group < HASH_SPLITPOINT_GROUPS_WITH_ONE_PHASE)
165150
return splitpoint_group;

Diff for: src/backend/utils/hash/dynahash.c

+7-7
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787

8888
#include "access/xact.h"
8989
#include "common/hashfn.h"
90+
#include "port/pg_bitutils.h"
9091
#include "storage/shmem.h"
9192
#include "storage/spin.h"
9293
#include "utils/dynahash.h"
@@ -1718,16 +1719,15 @@ hash_corrupted(HTAB *hashp)
17181719
int
17191720
my_log2(long num)
17201721
{
1721-
int i;
1722-
long limit;
1723-
1724-
/* guard against too-large input, which would put us into infinite loop */
1722+
/* guard against too-large input, which would be invalid for pg_ceil_log2_*() */
17251723
if (num > LONG_MAX / 2)
17261724
num = LONG_MAX / 2;
17271725

1728-
for (i = 0, limit = 1; limit < num; i++, limit <<= 1)
1729-
;
1730-
return i;
1726+
#if SIZEOF_LONG < 8
1727+
return pg_ceil_log2_32(num);
1728+
#else
1729+
return pg_ceil_log2_64(num);
1730+
#endif
17311731
}
17321732

17331733
/* calculate first power of 2 >= num, bounded to what will fit in a long */

Diff for: src/include/access/hash.h

-1
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,6 @@ extern uint32 _hash_datum2hashkey(Relation rel, Datum key);
451451
extern uint32 _hash_datum2hashkey_type(Relation rel, Datum key, Oid keytype);
452452
extern Bucket _hash_hashkey2bucket(uint32 hashkey, uint32 maxbucket,
453453
uint32 highmask, uint32 lowmask);
454-
extern uint32 _hash_log2(uint32 num);
455454
extern uint32 _hash_spareindex(uint32 num_bucket);
456455
extern uint32 _hash_get_totalbuckets(uint32 splitpoint_phase);
457456
extern void _hash_checkpage(Relation rel, Buffer buf, int flags);

Diff for: src/include/lib/simplehash.h

+4-23
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@
5757
* backwards, unless they're empty or already at their optimal position.
5858
*/
5959

60+
#include "port/pg_bitutils.h"
61+
6062
/* helpers */
6163
#define SH_MAKE_PREFIX(a) CppConcat(a,_)
6264
#define SH_MAKE_NAME(name) SH_MAKE_NAME_(SH_MAKE_PREFIX(SH_PREFIX),name)
@@ -215,27 +217,6 @@ SH_SCOPE void SH_STAT(SH_TYPE * tb);
215217
#ifndef SIMPLEHASH_H
216218
#define SIMPLEHASH_H
217219

218-
/* FIXME: can we move these to a central location? */
219-
220-
/* calculate ceil(log base 2) of num */
221-
static inline uint64
222-
sh_log2(uint64 num)
223-
{
224-
int i;
225-
uint64 limit;
226-
227-
for (i = 0, limit = 1; limit < num; i++, limit <<= 1)
228-
;
229-
return i;
230-
}
231-
232-
/* calculate first power of 2 >= num */
233-
static inline uint64
234-
sh_pow2(uint64 num)
235-
{
236-
return ((uint64) 1) << sh_log2(num);
237-
}
238-
239220
#ifdef FRONTEND
240221
#define sh_error(...) pg_log_error(__VA_ARGS__)
241222
#define sh_log(...) pg_log_info(__VA_ARGS__)
@@ -259,7 +240,7 @@ SH_COMPUTE_PARAMETERS(SH_TYPE * tb, uint32 newsize)
259240
size = Max(newsize, 2);
260241

261242
/* round up size to the next power of 2, that's how bucketing works */
262-
size = sh_pow2(size);
243+
size = pg_nextpower2_64(size);
263244
Assert(size <= SH_MAX_SIZE);
264245

265246
/*
@@ -434,7 +415,7 @@ SH_GROW(SH_TYPE * tb, uint32 newsize)
434415
uint32 startelem = 0;
435416
uint32 copyelem;
436417

437-
Assert(oldsize == sh_pow2(oldsize));
418+
Assert(oldsize == pg_nextpower2_64(oldsize));
438419
Assert(oldsize != SH_MAX_SIZE);
439420
Assert(oldsize < newsize);
440421

Diff for: src/include/port/pg_bitutils.h

+6
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,15 @@
1313
#ifndef PG_BITUTILS_H
1414
#define PG_BITUTILS_H
1515

16+
#ifndef FRONTEND
1617
extern PGDLLIMPORT const uint8 pg_leftmost_one_pos[256];
1718
extern PGDLLIMPORT const uint8 pg_rightmost_one_pos[256];
1819
extern PGDLLIMPORT const uint8 pg_number_of_ones[256];
20+
#else
21+
extern const uint8 pg_leftmost_one_pos[256];
22+
extern const uint8 pg_rightmost_one_pos[256];
23+
extern const uint8 pg_number_of_ones[256];
24+
#endif
1925

2026
/*
2127
* pg_leftmost_one_pos32

0 commit comments

Comments
 (0)