@@ -1847,7 +1847,8 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
1847
1847
*/
1848
1848
buffer = RelationGetBufferForTuple (relation , heaptup -> t_len ,
1849
1849
InvalidBuffer , options , bistate ,
1850
- & vmbuffer , NULL );
1850
+ & vmbuffer , NULL ,
1851
+ 0 );
1851
1852
1852
1853
/*
1853
1854
* 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,
2050
2051
return tup ;
2051
2052
}
2052
2053
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
+
2053
2080
/*
2054
2081
* heap_multi_insert - insert multiple tuples into a heap
2055
2082
*
@@ -2076,6 +2103,9 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
2076
2103
Size saveFreeSpace ;
2077
2104
bool need_tuple_data = RelationIsLogicallyLogged (relation );
2078
2105
bool need_cids = RelationIsAccessibleInLogicalDecoding (relation );
2106
+ bool starting_with_empty_page = false;
2107
+ int npages = 0 ;
2108
+ int npages_used = 0 ;
2079
2109
2080
2110
/* currently not needed (thus unsupported) for heap_multi_insert() */
2081
2111
Assert (!(options & HEAP_INSERT_NO_LOGICAL ));
@@ -2126,13 +2156,31 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
2126
2156
while (ndone < ntuples )
2127
2157
{
2128
2158
Buffer buffer ;
2129
- bool starting_with_empty_page ;
2130
2159
bool all_visible_cleared = false;
2131
2160
bool all_frozen_set = false;
2132
2161
int nthispage ;
2133
2162
2134
2163
CHECK_FOR_INTERRUPTS ();
2135
2164
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
+
2136
2184
/*
2137
2185
* Find buffer where at least the next tuple will fit. If the page is
2138
2186
* all-visible, this will also pin the requisite visibility map page.
@@ -2142,7 +2190,8 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
2142
2190
*/
2143
2191
buffer = RelationGetBufferForTuple (relation , heaptuples [ndone ]-> t_len ,
2144
2192
InvalidBuffer , options , bistate ,
2145
- & vmbuffer , NULL );
2193
+ & vmbuffer , NULL ,
2194
+ npages - npages_used );
2146
2195
page = BufferGetPage (buffer );
2147
2196
2148
2197
starting_with_empty_page = PageGetMaxOffsetNumber (page ) == 0 ;
@@ -3576,7 +3625,8 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
3576
3625
/* It doesn't fit, must use RelationGetBufferForTuple. */
3577
3626
newbuf = RelationGetBufferForTuple (relation , heaptup -> t_len ,
3578
3627
buffer , 0 , NULL ,
3579
- & vmbuffer_new , & vmbuffer );
3628
+ & vmbuffer_new , & vmbuffer ,
3629
+ 0 );
3580
3630
/* We're all done. */
3581
3631
break ;
3582
3632
}
0 commit comments