34
34
/* number of active words for a page: */
35
35
#define WORDS_PER_PAGE (n ) ((n) / BITS_PER_BITMAPWORD + 1)
36
36
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
+
37
40
/*
38
41
* This is named similarly to PagetableEntry in tidbitmap.c
39
42
* because the two have a similar function.
40
43
*/
41
44
typedef struct BlocktableEntry
42
45
{
43
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 ];
53
+
44
54
bitmapword words [FLEXIBLE_ARRAY_MEMBER ];
45
55
} BlocktableEntry ;
46
56
#define MaxBlocktableEntrySize \
@@ -331,33 +341,53 @@ TidStoreSetBlockOffsets(TidStore *ts, BlockNumber blkno, OffsetNumber *offsets,
331
341
for (int i = 1 ; i < num_offsets ; i ++ )
332
342
Assert (offsets [i ] > offsets [i - 1 ]);
333
343
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 ));
339
345
340
- while (idx < num_offsets )
346
+ if (num_offsets <= NUM_FULL_OFFSETS )
347
+ {
348
+ for (int i = 0 ; i < num_offsets ; i ++ )
341
349
{
342
- OffsetNumber off = offsets [idx ];
350
+ OffsetNumber off = offsets [i ];
343
351
344
352
/* safety check to ensure we don't overrun bit array bounds */
345
353
if (!OffsetNumberIsValid (off ))
346
354
elog (ERROR , "tuple offset out of range: %u" , off );
347
355
348
- if (off >= next_word_threshold )
349
- break ;
350
-
351
- word |= ((bitmapword ) 1 << BITNUM (off ));
352
- idx ++ ;
356
+ page -> full_offsets [i ] = off ;
353
357
}
354
358
355
- /* write out offset bitmap for this wordnum */
356
- page -> words [wordnum ] = word ;
359
+ page -> nwords = 0 ;
357
360
}
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
+ }
358
387
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
+ }
361
391
362
392
if (TidStoreIsShared (ts ))
363
393
shared_ts_set (ts -> tree .shared , blkno , page );
@@ -384,14 +414,27 @@ TidStoreIsMember(TidStore *ts, ItemPointer tid)
384
414
if (page == NULL )
385
415
return false;
386
416
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
+ }
392
425
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;
393
435
394
- return (page -> words [wordnum ] & ((bitmapword ) 1 << bitnum )) != 0 ;
436
+ return (page -> words [wordnum ] & ((bitmapword ) 1 << bitnum )) != 0 ;
437
+ }
395
438
}
396
439
397
440
/*
@@ -511,25 +554,37 @@ tidstore_iter_extract_tids(TidStoreIter *iter, BlockNumber blkno,
511
554
result -> num_offsets = 0 ;
512
555
result -> blkno = blkno ;
513
556
514
- for ( wordnum = 0 ; wordnum < page -> nwords ; wordnum ++ )
557
+ if ( page -> nwords == 0 )
515
558
{
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 ++ )
521
561
{
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 ];
525
564
}
526
-
527
- while (w != 0 )
565
+ }
566
+ else
567
+ {
568
+ for (wordnum = 0 ; wordnum < page -> nwords ; wordnum ++ )
528
569
{
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
+ }
533
588
}
534
589
}
535
590
}
0 commit comments