@@ -227,7 +227,7 @@ struct Tuplesortstate
227
227
int maxTapes ; /* number of tapes (Knuth's T) */
228
228
int tapeRange ; /* maxTapes-1 (Knuth's P) */
229
229
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 */
231
231
LogicalTapeSet * tapeset ; /* logtape.c object for tapes in a temp file */
232
232
233
233
/*
@@ -2536,8 +2536,11 @@ mergeonerun(Tuplesortstate *state)
2536
2536
}
2537
2537
2538
2538
/*
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.
2541
2544
*/
2542
2545
MemoryContextReset (state -> tuplecontext );
2543
2546
@@ -2710,10 +2713,21 @@ beginmerge(Tuplesortstate *state, bool finalMergeBatch)
2710
2713
* allocated slots. However, though slots and tuple memory is in balance
2711
2714
* following the last grow_memtuples() call, that's predicated on the observed
2712
2715
* 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.
2714
2719
*
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.
2717
2731
*/
2718
2732
static void
2719
2733
batchmemtuples (Tuplesortstate * state )
0 commit comments