3434/* number of active words for a page: */
3535#define WORDS_PER_PAGE (n ) ((n) / BITS_PER_BITMAPWORD + 1)
3636
37+ /* number of offsets we can store in the header of a BlocktableEntry */
38+ #define NUM_FULL_OFFSETS ((sizeof(bitmapword) - sizeof(uint16)) / sizeof(OffsetNumber))
39+
3740/*
3841 * This is named similarly to PagetableEntry in tidbitmap.c
3942 * because the two have a similar function.
4043 */
4144typedef struct BlocktableEntry
4245{
4346 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 ];
53+
4454 bitmapword words [FLEXIBLE_ARRAY_MEMBER ];
4555} BlocktableEntry ;
4656#define MaxBlocktableEntrySize \
@@ -331,33 +341,53 @@ TidStoreSetBlockOffsets(TidStore *ts, BlockNumber blkno, OffsetNumber *offsets,
331341 for (int i = 1 ; i < num_offsets ; i ++ )
332342 Assert (offsets [i ] > offsets [i - 1 ]);
333343
334- for (wordnum = 0 , next_word_threshold = BITS_PER_BITMAPWORD ;
335- wordnum <= WORDNUM (offsets [num_offsets - 1 ]);
336- wordnum ++ , next_word_threshold += BITS_PER_BITMAPWORD )
337- {
338- word = 0 ;
344+ memset (page , 0 , offsetof(BlocktableEntry , words ));
339345
340- while (idx < num_offsets )
346+ if (num_offsets <= NUM_FULL_OFFSETS )
347+ {
348+ for (int i = 0 ; i < num_offsets ; i ++ )
341349 {
342- OffsetNumber off = offsets [idx ];
350+ OffsetNumber off = offsets [i ];
343351
344352 /* safety check to ensure we don't overrun bit array bounds */
345353 if (!OffsetNumberIsValid (off ))
346354 elog (ERROR , "tuple offset out of range: %u" , off );
347355
348- if (off >= next_word_threshold )
349- break ;
350-
351- word |= ((bitmapword ) 1 << BITNUM (off ));
352- idx ++ ;
356+ page -> full_offsets [i ] = off ;
353357 }
354358
355- /* write out offset bitmap for this wordnum */
356- page -> words [wordnum ] = word ;
359+ page -> nwords = 0 ;
357360 }
361+ else
362+ {
363+ for (wordnum = 0 , next_word_threshold = BITS_PER_BITMAPWORD ;
364+ wordnum <= WORDNUM (offsets [num_offsets - 1 ]);
365+ wordnum ++ , next_word_threshold += BITS_PER_BITMAPWORD )
366+ {
367+ word = 0 ;
368+
369+ while (idx < num_offsets )
370+ {
371+ OffsetNumber off = offsets [idx ];
372+
373+ /* safety check to ensure we don't overrun bit array bounds */
374+ if (!OffsetNumberIsValid (off ))
375+ elog (ERROR , "tuple offset out of range: %u" , off );
376+
377+ if (off >= next_word_threshold )
378+ break ;
379+
380+ word |= ((bitmapword ) 1 << BITNUM (off ));
381+ idx ++ ;
382+ }
383+
384+ /* write out offset bitmap for this wordnum */
385+ page -> words [wordnum ] = word ;
386+ }
358387
359- page -> nwords = wordnum ;
360- Assert (page -> nwords == WORDS_PER_PAGE (offsets [num_offsets - 1 ]));
388+ page -> nwords = wordnum ;
389+ Assert (page -> nwords == WORDS_PER_PAGE (offsets [num_offsets - 1 ]));
390+ }
361391
362392 if (TidStoreIsShared (ts ))
363393 shared_ts_set (ts -> tree .shared , blkno , page );
@@ -384,14 +414,27 @@ TidStoreIsMember(TidStore *ts, ItemPointer tid)
384414 if (page == NULL )
385415 return false;
386416
387- wordnum = WORDNUM (off );
388- bitnum = BITNUM (off );
389-
390- /* no bitmap for the off */
391- if (wordnum >= page -> nwords )
417+ if (page -> nwords == 0 )
418+ {
419+ /* we have offsets in the header */
420+ for (int i = 0 ; i < NUM_FULL_OFFSETS ; i ++ )
421+ {
422+ if (page -> full_offsets [i ] == off )
423+ return true;
424+ }
392425 return false;
426+ }
427+ else
428+ {
429+ wordnum = WORDNUM (off );
430+ bitnum = BITNUM (off );
431+
432+ /* no bitmap for the off */
433+ if (wordnum >= page -> nwords )
434+ return false;
393435
394- return (page -> words [wordnum ] & ((bitmapword ) 1 << bitnum )) != 0 ;
436+ return (page -> words [wordnum ] & ((bitmapword ) 1 << bitnum )) != 0 ;
437+ }
395438}
396439
397440/*
@@ -511,25 +554,37 @@ tidstore_iter_extract_tids(TidStoreIter *iter, BlockNumber blkno,
511554 result -> num_offsets = 0 ;
512555 result -> blkno = blkno ;
513556
514- for ( wordnum = 0 ; wordnum < page -> nwords ; wordnum ++ )
557+ if ( page -> nwords == 0 )
515558 {
516- bitmapword w = page -> words [wordnum ];
517- int off = wordnum * BITS_PER_BITMAPWORD ;
518-
519- /* Make sure there is enough space to add offsets */
520- if ((result -> num_offsets + BITS_PER_BITMAPWORD ) > result -> max_offset )
559+ /* we have offsets in the header */
560+ for (int i = 0 ; i < NUM_FULL_OFFSETS ; i ++ )
521561 {
522- result -> max_offset *= 2 ;
523- result -> offsets = repalloc (result -> offsets ,
524- sizeof (OffsetNumber ) * result -> max_offset );
562+ if (page -> full_offsets [i ] != InvalidOffsetNumber )
563+ result -> offsets [result -> num_offsets ++ ] = page -> full_offsets [i ];
525564 }
526-
527- while (w != 0 )
565+ }
566+ else
567+ {
568+ for (wordnum = 0 ; wordnum < page -> nwords ; wordnum ++ )
528569 {
529- if (w & 1 )
530- result -> offsets [result -> num_offsets ++ ] = (OffsetNumber ) off ;
531- off ++ ;
532- w >>= 1 ;
570+ bitmapword w = page -> words [wordnum ];
571+ int off = wordnum * BITS_PER_BITMAPWORD ;
572+
573+ /* Make sure there is enough space to add offsets */
574+ if ((result -> num_offsets + BITS_PER_BITMAPWORD ) > result -> max_offset )
575+ {
576+ result -> max_offset *= 2 ;
577+ result -> offsets = repalloc (result -> offsets ,
578+ sizeof (OffsetNumber ) * result -> max_offset );
579+ }
580+
581+ while (w != 0 )
582+ {
583+ if (w & 1 )
584+ result -> offsets [result -> num_offsets ++ ] = (OffsetNumber ) off ;
585+ off ++ ;
586+ w >>= 1 ;
587+ }
533588 }
534589 }
535590}
0 commit comments