3535#define WORDS_PER_PAGE (n ) ((n) / BITS_PER_BITMAPWORD + 1)
3636
3737/* number of offsets we can store in the header of a BlocktableEntry */
38- #define NUM_FULL_OFFSETS ((sizeof(bitmapword ) - sizeof(uint16 )) / sizeof(OffsetNumber))
38+ #define NUM_FULL_OFFSETS ((sizeof(uintptr_t ) - sizeof(uint8) - sizeof(int8 )) / sizeof(OffsetNumber))
3939
4040/*
4141 * This is named similarly to PagetableEntry in tidbitmap.c
4242 * because the two have a similar function.
4343 */
4444typedef struct BlocktableEntry
4545{
46- uint16 nwords ;
47-
48- /*
49- * We can store a small number of offsets here to avoid wasting space with
50- * a sparse bitmap.
51- */
52- OffsetNumber full_offsets [NUM_FULL_OFFSETS ];
46+ union
47+ {
48+ struct
49+ {
50+ #ifndef WORDS_BIGENDIAN
51+ /*
52+ * We need to position this member so that the backing radix tree
53+ * can use the lowest bit for a pointer tag. In particular, it
54+ * must be placed within 'header' so that it corresponds to the
55+ * lowest byte in 'ptr'. We position 'nwords' along with it to
56+ * avoid struct padding.
57+ */
58+ uint8 flags ;
59+
60+ int8 nwords ;
61+ #endif
62+
63+ /*
64+ * We can store a small number of offsets here to avoid wasting
65+ * space with a sparse bitmap.
66+ */
67+ OffsetNumber full_offsets [NUM_FULL_OFFSETS ];
68+
69+ #ifdef WORDS_BIGENDIAN
70+ int8 nwords ;
71+ uint8 flags ;
72+ #endif
73+ };
74+ uintptr_t ptr ;
75+ } header ;
5376
5477 bitmapword words [FLEXIBLE_ARRAY_MEMBER ];
5578} BlocktableEntry ;
79+
80+ /*
81+ * The type of 'nwords' limits the max number of words in the 'words' array.
82+ * This computes the max offset we can actually store in the bitmap. In
83+ * practice, it's almost always the same as MaxOffsetNumber.
84+ */
85+ #define MAX_OFFSET_IN_BITMAP Min(BITS_PER_BITMAPWORD * PG_INT8_MAX - 1, MaxOffsetNumber)
86+
5687#define MaxBlocktableEntrySize \
5788 offsetof(BlocktableEntry, words) + \
58- (sizeof(bitmapword) * WORDS_PER_PAGE(MaxOffsetNumber ))
89+ (sizeof(bitmapword) * WORDS_PER_PAGE(MAX_OFFSET_IN_BITMAP ))
5990
6091#define RT_PREFIX local_ts
6192#define RT_SCOPE static
@@ -64,7 +95,8 @@ typedef struct BlocktableEntry
6495#define RT_VALUE_TYPE BlocktableEntry
6596#define RT_VARLEN_VALUE_SIZE (page ) \
6697 (offsetof(BlocktableEntry, words) + \
67- sizeof(bitmapword) * (page)->nwords)
98+ sizeof(bitmapword) * (page)->header.nwords)
99+ #define RT_RUNTIME_EMBEDDABLE_VALUE
68100#include "lib/radixtree.h"
69101
70102#define RT_PREFIX shared_ts
@@ -75,7 +107,8 @@ typedef struct BlocktableEntry
75107#define RT_VALUE_TYPE BlocktableEntry
76108#define RT_VARLEN_VALUE_SIZE (page ) \
77109 (offsetof(BlocktableEntry, words) + \
78- sizeof(bitmapword) * (page)->nwords)
110+ sizeof(bitmapword) * (page)->header.nwords)
111+ #define RT_RUNTIME_EMBEDDABLE_VALUE
79112#include "lib/radixtree.h"
80113
81114/* Per-backend state for a TidStore */
@@ -350,13 +383,13 @@ TidStoreSetBlockOffsets(TidStore *ts, BlockNumber blkno, OffsetNumber *offsets,
350383 OffsetNumber off = offsets [i ];
351384
352385 /* safety check to ensure we don't overrun bit array bounds */
353- if (! OffsetNumberIsValid ( off ) )
386+ if (off == InvalidOffsetNumber || off > MAX_OFFSET_IN_BITMAP )
354387 elog (ERROR , "tuple offset out of range: %u" , off );
355388
356- page -> full_offsets [i ] = off ;
389+ page -> header . full_offsets [i ] = off ;
357390 }
358391
359- page -> nwords = 0 ;
392+ page -> header . nwords = 0 ;
360393 }
361394 else
362395 {
@@ -371,7 +404,7 @@ TidStoreSetBlockOffsets(TidStore *ts, BlockNumber blkno, OffsetNumber *offsets,
371404 OffsetNumber off = offsets [idx ];
372405
373406 /* safety check to ensure we don't overrun bit array bounds */
374- if (! OffsetNumberIsValid ( off ) )
407+ if (off == InvalidOffsetNumber || off > MAX_OFFSET_IN_BITMAP )
375408 elog (ERROR , "tuple offset out of range: %u" , off );
376409
377410 if (off >= next_word_threshold )
@@ -385,8 +418,8 @@ TidStoreSetBlockOffsets(TidStore *ts, BlockNumber blkno, OffsetNumber *offsets,
385418 page -> words [wordnum ] = word ;
386419 }
387420
388- page -> nwords = wordnum ;
389- Assert (page -> nwords == WORDS_PER_PAGE (offsets [num_offsets - 1 ]));
421+ page -> header . nwords = wordnum ;
422+ Assert (page -> header . nwords == WORDS_PER_PAGE (offsets [num_offsets - 1 ]));
390423 }
391424
392425 if (TidStoreIsShared (ts ))
@@ -414,12 +447,12 @@ TidStoreIsMember(TidStore *ts, ItemPointer tid)
414447 if (page == NULL )
415448 return false;
416449
417- if (page -> nwords == 0 )
450+ if (page -> header . nwords == 0 )
418451 {
419452 /* we have offsets in the header */
420453 for (int i = 0 ; i < NUM_FULL_OFFSETS ; i ++ )
421454 {
422- if (page -> full_offsets [i ] == off )
455+ if (page -> header . full_offsets [i ] == off )
423456 return true;
424457 }
425458 return false;
@@ -430,7 +463,7 @@ TidStoreIsMember(TidStore *ts, ItemPointer tid)
430463 bitnum = BITNUM (off );
431464
432465 /* no bitmap for the off */
433- if (wordnum >= page -> nwords )
466+ if (wordnum >= page -> header . nwords )
434467 return false;
435468
436469 return (page -> words [wordnum ] & ((bitmapword ) 1 << bitnum )) != 0 ;
@@ -554,18 +587,18 @@ tidstore_iter_extract_tids(TidStoreIter *iter, BlockNumber blkno,
554587 result -> num_offsets = 0 ;
555588 result -> blkno = blkno ;
556589
557- if (page -> nwords == 0 )
590+ if (page -> header . nwords == 0 )
558591 {
559592 /* we have offsets in the header */
560593 for (int i = 0 ; i < NUM_FULL_OFFSETS ; i ++ )
561594 {
562- if (page -> full_offsets [i ] != InvalidOffsetNumber )
563- result -> offsets [result -> num_offsets ++ ] = page -> full_offsets [i ];
595+ if (page -> header . full_offsets [i ] != InvalidOffsetNumber )
596+ result -> offsets [result -> num_offsets ++ ] = page -> header . full_offsets [i ];
564597 }
565598 }
566599 else
567600 {
568- for (wordnum = 0 ; wordnum < page -> nwords ; wordnum ++ )
601+ for (wordnum = 0 ; wordnum < page -> header . nwords ; wordnum ++ )
569602 {
570603 bitmapword w = page -> words [wordnum ];
571604 int off = wordnum * BITS_PER_BITMAPWORD ;
0 commit comments