Fix accounting of memory needed for merge heap.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Thu, 8 Dec 2016 08:15:24 +0000 (10:15 +0200)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Thu, 8 Dec 2016 08:15:57 +0000 (10:15 +0200)
We allegedly allocated all remaining memory for the read buffers of the
sort tapes, but we allocated the merge heap only after that. That means
that the allocation of the merge heap was guaranteed to go over the memory
limit. Fix by allocating the merge heap first. This makes little difference
in practice, because the merge heap is tiny, but let's tidy.

While we're at it, add a safeguard for the case that we are already over
the limit when allocating the read buffers. That shouldn't happen, but
better safe than sorry.

The memory accounting error was reported off-list by Peter Geoghegan.

src/backend/utils/sort/tuplesort.c

index 3ad81862f35f125d245838193c7297211f825205..46eecbf942f77a11473e966416f8a62a0468de08 100644 (file)
@@ -2637,8 +2637,16 @@ mergeruns(Tuplesortstate *state)
    }
 
    /*
-    * Use all the spare memory we have available for read buffers among the
-    * input tapes.
+    * Allocate a new 'memtuples' array, for the heap.  It will hold one tuple
+    * from each input tape.
+    */
+   state->memtupsize = numInputTapes;
+   state->memtuples = (SortTuple *) palloc(numInputTapes * sizeof(SortTuple));
+   USEMEM(state, GetMemoryChunkSpace(state->memtuples));
+
+   /*
+    * Use all the remaining memory we have available for read buffers among
+    * the input tapes.
     *
     * We do this only after checking for the case that we produced only one
     * initial run, because there is no need to use a large read buffer when
@@ -2661,17 +2669,9 @@ mergeruns(Tuplesortstate *state)
             (state->availMem) / 1024, numInputTapes);
 #endif
 
-   state->read_buffer_size = state->availMem / numInputTapes;
+   state->read_buffer_size = Min(state->availMem / numInputTapes, 0);
    USEMEM(state, state->availMem);
 
-   /*
-    * Allocate a new 'memtuples' array, for the heap.  It will hold one tuple
-    * from each input tape.
-    */
-   state->memtupsize = numInputTapes;
-   state->memtuples = (SortTuple *) palloc(numInputTapes * sizeof(SortTuple));
-   USEMEM(state, GetMemoryChunkSpace(state->memtuples));
-
    /* End of step D2: rewind all output tapes to prepare for merging */
    for (tapenum = 0; tapenum < state->tapeRange; tapenum++)
        LogicalTapeRewindForRead(state->tapeset, tapenum, state->read_buffer_size);