Skip to content

Commit 5279e9d

Browse files
committed
heapam: Pass number of required pages to RelationGetBufferForTuple()
A future commit will use this information to determine how aggressively to extend the relation by. In heap_multi_insert() we know accurately how many pages we need once we need to extend the relation, providing an accurate lower bound for how much to extend. Reviewed-by: Melanie Plageman <melanieplageman@gmail.com> Discussion: https://postgr.es/m/20221029025420.eplyow6k7tgu6he3@awork3.anarazel.de
1 parent 7d71d3d commit 5279e9d

File tree

3 files changed

+63
-6
lines changed

3 files changed

+63
-6
lines changed

src/backend/access/heap/heapam.c

+54-4
Original file line numberDiff line numberDiff line change
@@ -1847,7 +1847,8 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
18471847
*/
18481848
buffer = RelationGetBufferForTuple(relation, heaptup->t_len,
18491849
InvalidBuffer, options, bistate,
1850-
&vmbuffer, NULL);
1850+
&vmbuffer, NULL,
1851+
0);
18511852

18521853
/*
18531854
* We're about to do the actual insert -- but check for conflict first, to
@@ -2050,6 +2051,32 @@ heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
20502051
return tup;
20512052
}
20522053

2054+
/*
2055+
* Helper for heap_multi_insert() that computes the number of entire pages
2056+
* that inserting the remaining heaptuples requires. Used to determine how
2057+
* much the relation needs to be extended by.
2058+
*/
2059+
static int
2060+
heap_multi_insert_pages(HeapTuple *heaptuples, int done, int ntuples, Size saveFreeSpace)
2061+
{
2062+
size_t page_avail = BLCKSZ - SizeOfPageHeaderData - saveFreeSpace;
2063+
int npages = 1;
2064+
2065+
for (int i = done; i < ntuples; i++)
2066+
{
2067+
size_t tup_sz = sizeof(ItemIdData) + MAXALIGN(heaptuples[i]->t_len);
2068+
2069+
if (page_avail < tup_sz)
2070+
{
2071+
npages++;
2072+
page_avail = BLCKSZ - SizeOfPageHeaderData - saveFreeSpace;
2073+
}
2074+
page_avail -= tup_sz;
2075+
}
2076+
2077+
return npages;
2078+
}
2079+
20532080
/*
20542081
* heap_multi_insert - insert multiple tuples into a heap
20552082
*
@@ -2076,6 +2103,9 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
20762103
Size saveFreeSpace;
20772104
bool need_tuple_data = RelationIsLogicallyLogged(relation);
20782105
bool need_cids = RelationIsAccessibleInLogicalDecoding(relation);
2106+
bool starting_with_empty_page = false;
2107+
int npages = 0;
2108+
int npages_used = 0;
20792109

20802110
/* currently not needed (thus unsupported) for heap_multi_insert() */
20812111
Assert(!(options & HEAP_INSERT_NO_LOGICAL));
@@ -2126,13 +2156,31 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
21262156
while (ndone < ntuples)
21272157
{
21282158
Buffer buffer;
2129-
bool starting_with_empty_page;
21302159
bool all_visible_cleared = false;
21312160
bool all_frozen_set = false;
21322161
int nthispage;
21332162

21342163
CHECK_FOR_INTERRUPTS();
21352164

2165+
/*
2166+
* Compute number of pages needed to fit the to-be-inserted tuples in
2167+
* the worst case. This will be used to determine how much to extend
2168+
* the relation by in RelationGetBufferForTuple(), if needed. If we
2169+
* filled a prior page from scratch, we can just update our last
2170+
* computation, but if we started with a partially filled page,
2171+
* recompute from scratch, the number of potentially required pages
2172+
* can vary due to tuples needing to fit onto the page, page headers
2173+
* etc.
2174+
*/
2175+
if (ndone == 0 || !starting_with_empty_page)
2176+
{
2177+
npages = heap_multi_insert_pages(heaptuples, ndone, ntuples,
2178+
saveFreeSpace);
2179+
npages_used = 0;
2180+
}
2181+
else
2182+
npages_used++;
2183+
21362184
/*
21372185
* Find buffer where at least the next tuple will fit. If the page is
21382186
* all-visible, this will also pin the requisite visibility map page.
@@ -2142,7 +2190,8 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
21422190
*/
21432191
buffer = RelationGetBufferForTuple(relation, heaptuples[ndone]->t_len,
21442192
InvalidBuffer, options, bistate,
2145-
&vmbuffer, NULL);
2193+
&vmbuffer, NULL,
2194+
npages - npages_used);
21462195
page = BufferGetPage(buffer);
21472196

21482197
starting_with_empty_page = PageGetMaxOffsetNumber(page) == 0;
@@ -3576,7 +3625,8 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
35763625
/* It doesn't fit, must use RelationGetBufferForTuple. */
35773626
newbuf = RelationGetBufferForTuple(relation, heaptup->t_len,
35783627
buffer, 0, NULL,
3579-
&vmbuffer_new, &vmbuffer);
3628+
&vmbuffer_new, &vmbuffer,
3629+
0);
35803630
/* We're all done. */
35813631
break;
35823632
}

src/backend/access/heap/hio.c

+7-1
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,11 @@ RelationAddExtraBlocks(Relation relation, BulkInsertState bistate)
301301
* Returns pinned and exclusive-locked buffer of a page in given relation
302302
* with free space >= given len.
303303
*
304+
* If num_pages is > 1, we will try to extend the relation by at least that
305+
* many pages when we decide to extend the relation. This is more efficient
306+
* for callers that know they will need multiple pages
307+
* (e.g. heap_multi_insert()).
308+
*
304309
* If otherBuffer is not InvalidBuffer, then it references a previously
305310
* pinned buffer of another page in the same relation; on return, this
306311
* buffer will also be exclusive-locked. (This case is used by heap_update;
@@ -359,7 +364,8 @@ Buffer
359364
RelationGetBufferForTuple(Relation relation, Size len,
360365
Buffer otherBuffer, int options,
361366
BulkInsertState bistate,
362-
Buffer *vmbuffer, Buffer *vmbuffer_other)
367+
Buffer *vmbuffer, Buffer *vmbuffer_other,
368+
int num_pages)
363369
{
364370
bool use_fsm = !(options & HEAP_INSERT_SKIP_FSM);
365371
Buffer buffer = InvalidBuffer;

src/include/access/hio.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ extern void RelationPutHeapTuple(Relation relation, Buffer buffer,
3838
extern Buffer RelationGetBufferForTuple(Relation relation, Size len,
3939
Buffer otherBuffer, int options,
4040
BulkInsertStateData *bistate,
41-
Buffer *vmbuffer, Buffer *vmbuffer_other);
41+
Buffer *vmbuffer, Buffer *vmbuffer_other,
42+
int num_pages);
4243

4344
#endif /* HIO_H */

0 commit comments

Comments
 (0)