Skip to content

Commit 2040bb4

Browse files
committed
Clean up manipulations of hash indexes' hasho_flag field.
Standardize on testing a hash index page's type by doing (opaque->hasho_flag & LH_PAGE_TYPE) == LH_xxx_PAGE Various places were taking shortcuts like opaque->hasho_flag & LH_BUCKET_PAGE which while not actually wrong, is still bad practice because it encourages use of opaque->hasho_flag & LH_UNUSED_PAGE which *is* wrong (LH_UNUSED_PAGE == 0, so the above is constant false). hash_xlog.c's hash_mask() contained such an incorrect test. This also ensures that we mask out the additional flag bits that hasho_flag has accreted since 9.6. pgstattuple's pgstat_hash_page(), for one, was failing to do that and was thus actively broken. Also fix assorted comments that hadn't been updated to reflect the extended usage of hasho_flag, and fix some macros that were testing just "(hasho_flag & bit)" to use the less dangerous, project-approved form "((hasho_flag & bit) != 0)". Coverity found the bug in hash_mask(); I noted the one in pgstat_hash_page() through code reading.
1 parent 1dffabe commit 2040bb4

File tree

6 files changed

+29
-25
lines changed

6 files changed

+29
-25
lines changed

contrib/pageinspect/hashfuncs.c

+7-5
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,8 @@ hash_page_type(PG_FUNCTION_ARGS)
184184
bytea *raw_page = PG_GETARG_BYTEA_P(0);
185185
Page page;
186186
HashPageOpaque opaque;
187-
char *type;
187+
int pagetype;
188+
const char *type;
188189

189190
if (!superuser())
190191
ereport(ERROR,
@@ -200,13 +201,14 @@ hash_page_type(PG_FUNCTION_ARGS)
200201
opaque = (HashPageOpaque) PageGetSpecialPointer(page);
201202

202203
/* page type (flags) */
203-
if (opaque->hasho_flag & LH_META_PAGE)
204+
pagetype = opaque->hasho_flag & LH_PAGE_TYPE;
205+
if (pagetype == LH_META_PAGE)
204206
type = "metapage";
205-
else if (opaque->hasho_flag & LH_OVERFLOW_PAGE)
207+
else if (pagetype == LH_OVERFLOW_PAGE)
206208
type = "overflow";
207-
else if (opaque->hasho_flag & LH_BUCKET_PAGE)
209+
else if (pagetype == LH_BUCKET_PAGE)
208210
type = "bucket";
209-
else if (opaque->hasho_flag & LH_BITMAP_PAGE)
211+
else if (pagetype == LH_BITMAP_PAGE)
210212
type = "bitmap";
211213
else
212214
type = "unused";

contrib/pgstattuple/pgstattuple.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ pgstat_hash_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno,
453453
HashPageOpaque opaque;
454454

455455
opaque = (HashPageOpaque) PageGetSpecialPointer(page);
456-
switch (opaque->hasho_flag)
456+
switch (opaque->hasho_flag & LH_PAGE_TYPE)
457457
{
458458
case LH_UNUSED_PAGE:
459459
stat->free_space += BLCKSZ;

src/backend/access/hash/hash_xlog.c

+5-3
Original file line numberDiff line numberDiff line change
@@ -1234,6 +1234,7 @@ hash_mask(char *pagedata, BlockNumber blkno)
12341234
{
12351235
Page page = (Page) pagedata;
12361236
HashPageOpaque opaque;
1237+
int pagetype;
12371238

12381239
mask_page_lsn(page);
12391240

@@ -1242,15 +1243,16 @@ hash_mask(char *pagedata, BlockNumber blkno)
12421243

12431244
opaque = (HashPageOpaque) PageGetSpecialPointer(page);
12441245

1245-
if (opaque->hasho_flag & LH_UNUSED_PAGE)
1246+
pagetype = opaque->hasho_flag & LH_PAGE_TYPE;
1247+
if (pagetype == LH_UNUSED_PAGE)
12461248
{
12471249
/*
12481250
* Mask everything on a UNUSED page.
12491251
*/
12501252
mask_page_content(page);
12511253
}
1252-
else if ((opaque->hasho_flag & LH_BUCKET_PAGE) ||
1253-
(opaque->hasho_flag & LH_OVERFLOW_PAGE))
1254+
else if (pagetype == LH_BUCKET_PAGE ||
1255+
pagetype == LH_OVERFLOW_PAGE)
12541256
{
12551257
/*
12561258
* In hash bucket and overflow pages, it is possible to modify the

src/backend/access/hash/hashovfl.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ _hash_addovflpage(Relation rel, Buffer metabuf, Buffer buf, bool retain_pin)
168168
if (retain_pin)
169169
{
170170
/* pin will be retained only for the primary bucket page */
171-
Assert(pageopaque->hasho_flag & LH_BUCKET_PAGE);
171+
Assert((pageopaque->hasho_flag & LH_PAGE_TYPE) == LH_BUCKET_PAGE);
172172
LockBuffer(buf, BUFFER_LOCK_UNLOCK);
173173
}
174174
else

src/backend/access/hash/hashutil.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,8 @@ _hash_get_totalbuckets(uint32 splitpoint_phase)
218218
/*
219219
* _hash_checkpage -- sanity checks on the format of all hash pages
220220
*
221-
* If flags is not zero, it is a bitwise OR of the acceptable values of
222-
* hasho_flag.
221+
* If flags is not zero, it is a bitwise OR of the acceptable page types
222+
* (values of hasho_flag & LH_PAGE_TYPE).
223223
*/
224224
void
225225
_hash_checkpage(Relation rel, Buffer buf, int flags)

src/include/access/hash.h

+13-13
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,13 @@ typedef uint32 Bucket;
4141
/*
4242
* Special space for hash index pages.
4343
*
44-
* hasho_flag tells us which type of page we're looking at. For
45-
* example, knowing overflow pages from bucket pages is necessary
46-
* information when you're deleting tuples from a page. If all the
47-
* tuples are deleted from an overflow page, the overflow is made
48-
* available to other buckets by calling _hash_freeovflpage(). If all
49-
* the tuples are deleted from a bucket page, no additional action is
50-
* necessary.
44+
* hasho_flag's LH_PAGE_TYPE bits tell us which type of page we're looking at.
45+
* Additional bits in the flag word are used for more transient purposes.
46+
*
47+
* To test a page's type, do (hasho_flag & LH_PAGE_TYPE) == LH_xxx_PAGE.
48+
* However, we ensure that each used page type has a distinct bit so that
49+
* we can OR together page types for uses such as the allowable-page-types
50+
* argument of _hash_checkpage().
5151
*/
5252
#define LH_UNUSED_PAGE (0)
5353
#define LH_OVERFLOW_PAGE (1 << 0)
@@ -60,7 +60,7 @@ typedef uint32 Bucket;
6060
#define LH_PAGE_HAS_DEAD_TUPLES (1 << 7)
6161

6262
#define LH_PAGE_TYPE \
63-
(LH_OVERFLOW_PAGE|LH_BUCKET_PAGE|LH_BITMAP_PAGE|LH_META_PAGE)
63+
(LH_OVERFLOW_PAGE | LH_BUCKET_PAGE | LH_BITMAP_PAGE | LH_META_PAGE)
6464

6565
/*
6666
* In an overflow page, hasho_prevblkno stores the block number of the previous
@@ -78,16 +78,16 @@ typedef struct HashPageOpaqueData
7878
BlockNumber hasho_prevblkno; /* see above */
7979
BlockNumber hasho_nextblkno; /* see above */
8080
Bucket hasho_bucket; /* bucket number this pg belongs to */
81-
uint16 hasho_flag; /* page type code, see above */
81+
uint16 hasho_flag; /* page type code + flag bits, see above */
8282
uint16 hasho_page_id; /* for identification of hash indexes */
8383
} HashPageOpaqueData;
8484

8585
typedef HashPageOpaqueData *HashPageOpaque;
8686

87-
#define H_NEEDS_SPLIT_CLEANUP(opaque) ((opaque)->hasho_flag & LH_BUCKET_NEEDS_SPLIT_CLEANUP)
88-
#define H_BUCKET_BEING_SPLIT(opaque) ((opaque)->hasho_flag & LH_BUCKET_BEING_SPLIT)
89-
#define H_BUCKET_BEING_POPULATED(opaque) ((opaque)->hasho_flag & LH_BUCKET_BEING_POPULATED)
90-
#define H_HAS_DEAD_TUPLES(opaque) ((opaque)->hasho_flag & LH_PAGE_HAS_DEAD_TUPLES)
87+
#define H_NEEDS_SPLIT_CLEANUP(opaque) (((opaque)->hasho_flag & LH_BUCKET_NEEDS_SPLIT_CLEANUP) != 0)
88+
#define H_BUCKET_BEING_SPLIT(opaque) (((opaque)->hasho_flag & LH_BUCKET_BEING_SPLIT) != 0)
89+
#define H_BUCKET_BEING_POPULATED(opaque) (((opaque)->hasho_flag & LH_BUCKET_BEING_POPULATED) != 0)
90+
#define H_HAS_DEAD_TUPLES(opaque) (((opaque)->hasho_flag & LH_PAGE_HAS_DEAD_TUPLES) != 0)
9191

9292
/*
9393
* The page ID is for the convenience of pg_filedump and similar utilities,

0 commit comments

Comments
 (0)