diff src/backend/utils/sort/tuplesort.c index ce27e40..80ac11b *** a/src/backend/utils/sort/tuplesort.c --- b/src/backend/utils/sort/tuplesort.c *************** tuplesort_end(Tuplesortstate *state) *** 957,970 **** * Grow the memtuples[] array, if possible within our memory constraint. * Return TRUE if able to enlarge the array, FALSE if not. * ! * At each increment we double the size of the array. When we are short ! * on memory we could consider smaller increases, but because availMem ! * moves around with tuple addition/removal, this might result in thrashing. ! * Small increases in the array size are likely to be pretty inefficient. */ static bool grow_memtuples(Tuplesortstate *state) { /* * We need to be sure that we do not cause LACKMEM to become true, else * the space management algorithm will go nuts. We assume here that the --- 957,974 ---- * Grow the memtuples[] array, if possible within our memory constraint. * Return TRUE if able to enlarge the array, FALSE if not. * ! * At each increment we double the size of the array. When we are short on ! * memory we do attempt one last, smaller increase. This only happens at most ! * once, since availMem moves around with tuple addition/removal. To do othewise ! * might result in thrashing. This is nothing more than a last-ditch effort to ! * avoid exceeding allowedMem, an undesirable outcome if avoidable. */ static bool grow_memtuples(Tuplesortstate *state) { + int newmemtupsize; + long memNowUsed = state->allowedMem - state->availMem; + /* * We need to be sure that we do not cause LACKMEM to become true, else * the space management algorithm will go nuts. We assume here that the *************** grow_memtuples(Tuplesortstate *state) *** 974,991 **** * enough to force palloc to treat it as a separate chunk, so this * assumption should be good. But let's check it.) */ ! if (state->availMem <= (long) (state->memtupsize * sizeof(SortTuple))) ! return false; /* * On a 64-bit machine, allowedMem could be high enough to get us into * trouble with MaxAllocSize, too. */ ! if ((Size) (state->memtupsize * 2) >= MaxAllocSize / sizeof(SortTuple)) return false; FREEMEM(state, GetMemoryChunkSpace(state->memtuples)); ! state->memtupsize *= 2; state->memtuples = (SortTuple *) repalloc(state->memtuples, state->memtupsize * sizeof(SortTuple)); --- 978,1020 ---- * enough to force palloc to treat it as a separate chunk, so this * assumption should be good. But let's check it.) */ ! if (memNowUsed > state->availMem) ! { ! int memtupsize = state->memtupsize; ! long allowedMem = state->allowedMem; ! ! /* ! * For this last increment, abandon doubling strategy. ! * ! * Use the known size (in bytes) of the tuples seen so far to estimate a ! * memtuples size that is just within our constraint. This is nothing ! * more than a heuristic. ! * ! * N.B. We rely on the assumption that nothing other than memtuples and ! * individual tuple storage has been deducted from availMem. ! */ ! newmemtupsize = memtupsize * allowedMem / memNowUsed; ! ! Assert(newmemtupsize <= state->memtupsize * 2); ! ! /* This may not be our first time through */ ! if (newmemtupsize <= memtupsize) ! return false; ! } ! else ! { ! newmemtupsize = state->memtupsize * 2; ! } /* * On a 64-bit machine, allowedMem could be high enough to get us into * trouble with MaxAllocSize, too. */ ! if ((Size) (newmemtupsize) >= MaxAllocSize / sizeof(SortTuple)) return false; FREEMEM(state, GetMemoryChunkSpace(state->memtuples)); ! state->memtupsize = newmemtupsize; state->memtuples = (SortTuple *) repalloc(state->memtuples, state->memtupsize * sizeof(SortTuple));