@@ -227,7 +227,7 @@ struct Tuplesortstate
227227 int maxTapes ; /* number of tapes (Knuth's T) */
228228 int tapeRange ; /* maxTapes-1 (Knuth's P) */
229229 MemoryContext sortcontext ; /* memory context holding most sort data */
230- MemoryContext tuplecontext ; /* memory context holding tuple data */
230+ MemoryContext tuplecontext ; /* sub- context of sortcontext for tuple data */
231231 LogicalTapeSet * tapeset ; /* logtape.c object for tapes in a temp file */
232232
233233 /*
@@ -2536,8 +2536,11 @@ mergeonerun(Tuplesortstate *state)
25362536 }
25372537
25382538 /*
2539- * Reset tuple memory, now that no caller tuples are needed in memory.
2540- * This prevents fragmentation.
2539+ * Reset tuple memory. We've freed all of the tuples that we previously
2540+ * allocated, but AllocSetFree will have put those chunks of memory on
2541+ * particular free lists, bucketed by size class. Thus, although all of
2542+ * that memory is free, it is effectively fragmented. Resetting the
2543+ * context gets us out from under that problem.
25412544 */
25422545 MemoryContextReset (state -> tuplecontext );
25432546
@@ -2710,10 +2713,21 @@ beginmerge(Tuplesortstate *state, bool finalMergeBatch)
27102713 * allocated slots. However, though slots and tuple memory is in balance
27112714 * following the last grow_memtuples() call, that's predicated on the observed
27122715 * average tuple size for the "final" grow_memtuples() call, which includes
2713- * palloc overhead.
2716+ * palloc overhead. During the final merge pass, where we will arrange to
2717+ * squeeze out the palloc overhead, we might need more slots in the memtuples
2718+ * array.
27142719 *
2715- * This will perform an actual final grow_memtuples() call without any palloc()
2716- * overhead, rebalancing the use of memory between slots and tuples.
2720+ * To make that happen, arrange for the amount of remaining memory to be
2721+ * exactly equal to the palloc overhead multiplied by the current size of
2722+ * the memtuples array, force the grow_memtuples flag back to true (it's
2723+ * probably but not necessarily false on entry to this routine), and then
2724+ * call grow_memtuples. This simulates loading enough tuples to fill the
2725+ * whole memtuples array and then having some space left over because of the
2726+ * elided palloc overhead. We expect that grow_memtuples() will conclude that
2727+ * it can't double the size of the memtuples array but that it can increase
2728+ * it by some percentage; but if it does decide to double it, that just means
2729+ * that we've never managed to use many slots in the memtuples array, in which
2730+ * case doubling it shouldn't hurt anything anyway.
27172731 */
27182732static void
27192733batchmemtuples (Tuplesortstate * state )
0 commit comments