Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit f6bef36

Browse files
committed
Refactor tidstore.c iterator buffering.
Previously, TidStoreIterateNext() would expand the set of offsets for each block into an internal buffer that it overwrote each time. In order to be able to collect the offsets for multiple blocks before working with them, change the contract. Now, the offsets are obtained by a separate call to TidStoreGetBlockOffsets(), which can be called at a later time. TidStoreIteratorResult objects are safe to copy and store in a queue. Reviewed-by: Noah Misch <noah@leadboat.com> Discussion: https://postgr.es/m/CAAKRu_bbkmwAzSBgnezancgJeXrQZXy4G4kBTd+5=cr86H5yew@mail.gmail.com
1 parent 1462aad commit f6bef36

File tree

4 files changed

+51
-42
lines changed

4 files changed

+51
-42
lines changed

src/backend/access/common/tidstore.c

+29-34
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,6 @@ struct TidStoreIter
147147
TidStoreIterResult output;
148148
};
149149

150-
static void tidstore_iter_extract_tids(TidStoreIter *iter, BlockNumber blkno,
151-
BlocktableEntry *page);
152-
153150
/*
154151
* Create a TidStore. The TidStore will live in the memory context that is
155152
* CurrentMemoryContext at the time of this call. The TID storage, backed
@@ -486,13 +483,6 @@ TidStoreBeginIterate(TidStore *ts)
486483
iter = palloc0(sizeof(TidStoreIter));
487484
iter->ts = ts;
488485

489-
/*
490-
* We start with an array large enough to contain at least the offsets
491-
* from one completely full bitmap element.
492-
*/
493-
iter->output.max_offset = 2 * BITS_PER_BITMAPWORD;
494-
iter->output.offsets = palloc(sizeof(OffsetNumber) * iter->output.max_offset);
495-
496486
if (TidStoreIsShared(ts))
497487
iter->tree_iter.shared = shared_ts_begin_iterate(ts->tree.shared);
498488
else
@@ -503,9 +493,9 @@ TidStoreBeginIterate(TidStore *ts)
503493

504494

505495
/*
506-
* Scan the TidStore and return the TIDs of the next block. The offsets in
507-
* each iteration result are ordered, as are the block numbers over all
508-
* iterations.
496+
* Return a result that contains the next block number and that can be used to
497+
* obtain the set of offsets by calling TidStoreGetBlockOffsets(). The result
498+
* is copyable.
509499
*/
510500
TidStoreIterResult *
511501
TidStoreIterateNext(TidStoreIter *iter)
@@ -521,8 +511,8 @@ TidStoreIterateNext(TidStoreIter *iter)
521511
if (page == NULL)
522512
return NULL;
523513

524-
/* Collect TIDs from the key-value pair */
525-
tidstore_iter_extract_tids(iter, (BlockNumber) key, page);
514+
iter->output.blkno = key;
515+
iter->output.internal_page = page;
526516

527517
return &(iter->output);
528518
}
@@ -540,7 +530,6 @@ TidStoreEndIterate(TidStoreIter *iter)
540530
else
541531
local_ts_end_iterate(iter->tree_iter.local);
542532

543-
pfree(iter->output.offsets);
544533
pfree(iter);
545534
}
546535

@@ -575,24 +564,32 @@ TidStoreGetHandle(TidStore *ts)
575564
return (dsa_pointer) shared_ts_get_handle(ts->tree.shared);
576565
}
577566

578-
/* Extract TIDs from the given key-value pair */
579-
static void
580-
tidstore_iter_extract_tids(TidStoreIter *iter, BlockNumber blkno,
581-
BlocktableEntry *page)
567+
/*
568+
* Given a TidStoreIterResult returned by TidStoreIterateNext(), extract the
569+
* offset numbers. Returns the number of offsets filled in, if <=
570+
* max_offsets. Otherwise, fills in as much as it can in the given space, and
571+
* returns the size of the buffer that would be needed.
572+
*/
573+
int
574+
TidStoreGetBlockOffsets(TidStoreIterResult *result,
575+
OffsetNumber *offsets,
576+
int max_offsets)
582577
{
583-
TidStoreIterResult *result = (&iter->output);
578+
BlocktableEntry *page = result->internal_page;
579+
int num_offsets = 0;
584580
int wordnum;
585581

586-
result->num_offsets = 0;
587-
result->blkno = blkno;
588-
589582
if (page->header.nwords == 0)
590583
{
591584
/* we have offsets in the header */
592585
for (int i = 0; i < NUM_FULL_OFFSETS; i++)
593586
{
594587
if (page->header.full_offsets[i] != InvalidOffsetNumber)
595-
result->offsets[result->num_offsets++] = page->header.full_offsets[i];
588+
{
589+
if (num_offsets < max_offsets)
590+
offsets[num_offsets] = page->header.full_offsets[i];
591+
num_offsets++;
592+
}
596593
}
597594
}
598595
else
@@ -602,21 +599,19 @@ tidstore_iter_extract_tids(TidStoreIter *iter, BlockNumber blkno,
602599
bitmapword w = page->words[wordnum];
603600
int off = wordnum * BITS_PER_BITMAPWORD;
604601

605-
/* Make sure there is enough space to add offsets */
606-
if ((result->num_offsets + BITS_PER_BITMAPWORD) > result->max_offset)
607-
{
608-
result->max_offset *= 2;
609-
result->offsets = repalloc(result->offsets,
610-
sizeof(OffsetNumber) * result->max_offset);
611-
}
612-
613602
while (w != 0)
614603
{
615604
if (w & 1)
616-
result->offsets[result->num_offsets++] = (OffsetNumber) off;
605+
{
606+
if (num_offsets < max_offsets)
607+
offsets[num_offsets] = (OffsetNumber) off;
608+
num_offsets++;
609+
}
617610
off++;
618611
w >>= 1;
619612
}
620613
}
621614
}
615+
616+
return num_offsets;
622617
}

src/backend/access/heap/vacuumlazy.c

+7-2
Original file line numberDiff line numberDiff line change
@@ -2126,12 +2126,17 @@ lazy_vacuum_heap_rel(LVRelState *vacrel)
21262126
Buffer buf;
21272127
Page page;
21282128
Size freespace;
2129+
OffsetNumber offsets[MaxOffsetNumber];
2130+
int num_offsets;
21292131

21302132
vacuum_delay_point();
21312133

21322134
blkno = iter_result->blkno;
21332135
vacrel->blkno = blkno;
21342136

2137+
num_offsets = TidStoreGetBlockOffsets(iter_result, offsets, lengthof(offsets));
2138+
Assert(num_offsets <= lengthof(offsets));
2139+
21352140
/*
21362141
* Pin the visibility map page in case we need to mark the page
21372142
* all-visible. In most cases this will be very cheap, because we'll
@@ -2143,8 +2148,8 @@ lazy_vacuum_heap_rel(LVRelState *vacrel)
21432148
buf = ReadBufferExtended(vacrel->rel, MAIN_FORKNUM, blkno, RBM_NORMAL,
21442149
vacrel->bstrategy);
21452150
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
2146-
lazy_vacuum_heap_page(vacrel, blkno, buf, iter_result->offsets,
2147-
iter_result->num_offsets, vmbuffer);
2151+
lazy_vacuum_heap_page(vacrel, blkno, buf, offsets,
2152+
num_offsets, vmbuffer);
21482153

21492154
/* Now that we've vacuumed the page, record its available space */
21502155
page = BufferGetPage(buf);

src/include/access/tidstore.h

+8-4
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,14 @@
2020
typedef struct TidStore TidStore;
2121
typedef struct TidStoreIter TidStoreIter;
2222

23-
/* Result struct for TidStoreIterateNext */
23+
/*
24+
* Result struct for TidStoreIterateNext. This is copyable, but should be
25+
* treated as opaque. Call TidStoreGetOffsets() to obtain the offsets.
26+
*/
2427
typedef struct TidStoreIterResult
2528
{
2629
BlockNumber blkno;
27-
int max_offset;
28-
int num_offsets;
29-
OffsetNumber *offsets;
30+
void *internal_page;
3031
} TidStoreIterResult;
3132

3233
extern TidStore *TidStoreCreateLocal(size_t max_bytes, bool insert_only);
@@ -42,6 +43,9 @@ extern void TidStoreSetBlockOffsets(TidStore *ts, BlockNumber blkno, OffsetNumbe
4243
extern bool TidStoreIsMember(TidStore *ts, ItemPointer tid);
4344
extern TidStoreIter *TidStoreBeginIterate(TidStore *ts);
4445
extern TidStoreIterResult *TidStoreIterateNext(TidStoreIter *iter);
46+
extern int TidStoreGetBlockOffsets(TidStoreIterResult *result,
47+
OffsetNumber *offsets,
48+
int max_offsets);
4549
extern void TidStoreEndIterate(TidStoreIter *iter);
4650
extern size_t TidStoreMemoryUsage(TidStore *ts);
4751
extern dsa_pointer TidStoreGetHandle(TidStore *ts);

src/test/modules/test_tidstore/test_tidstore.c

+7-2
Original file line numberDiff line numberDiff line change
@@ -267,9 +267,14 @@ check_set_block_offsets(PG_FUNCTION_ARGS)
267267
iter = TidStoreBeginIterate(tidstore);
268268
while ((iter_result = TidStoreIterateNext(iter)) != NULL)
269269
{
270-
for (int i = 0; i < iter_result->num_offsets; i++)
270+
OffsetNumber offsets[MaxOffsetNumber];
271+
int num_offsets;
272+
273+
num_offsets = TidStoreGetBlockOffsets(iter_result, offsets, lengthof(offsets));
274+
Assert(num_offsets <= lengthof(offsets));
275+
for (int i = 0; i < num_offsets; i++)
271276
ItemPointerSet(&(items.iter_tids[num_iter_tids++]), iter_result->blkno,
272-
iter_result->offsets[i]);
277+
offsets[i]);
273278
}
274279
TidStoreEndIterate(iter);
275280
TidStoreUnlock(tidstore);

0 commit comments

Comments
 (0)