aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/sort/tuplesort.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2015-08-04 18:18:46 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2015-08-04 18:18:46 -0400
commit8ea3e7a75c0d22c41c57f59c8b367059b97d0b66 (patch)
tree37658922d3ff3abf63984cd29f4a9a56a4e16484 /src/backend/utils/sort/tuplesort.c
parent85e5e222b1dd02f135a8c3bf387d0d6d88e669bd (diff)
downloadpostgresql-8ea3e7a75c0d22c41c57f59c8b367059b97d0b66.tar.gz
postgresql-8ea3e7a75c0d22c41c57f59c8b367059b97d0b66.zip
Fix bogus "out of memory" reports in tuplestore.c.
The tuplesort/tuplestore memory management logic assumed that the chunk allocation overhead for its memtuples array could not increase when increasing the array size. This is and always was true for tuplesort, but we (I, I think) blindly copied that logic into tuplestore.c without noticing that the assumption failed to hold for the much smaller array elements used by tuplestore. Given rather small work_mem, this could result in an improper complaint about "unexpected out-of-memory situation", as reported by Brent DeSpain in bug #13530. The easiest way to fix this is just to increase tuplestore's initial array size so that the assumption holds. Rather than relying on magic constants, though, let's export a #define from aset.c that represents the safe allocation threshold, and make tuplestore's calculation depend on that. Do the same in tuplesort.c to keep the logic looking parallel, even though tuplesort.c isn't actually at risk at present. This will keep us from breaking it if we ever muck with the allocation parameters in aset.c. Back-patch to all supported versions. The error message doesn't occur pre-9.3, not so much because the problem can't happen as because the pre-9.3 tuplestore code neglected to check for it. (The chance of trouble is a great deal larger as of 9.3, though, due to changes in the array-size-increasing strategy.) However, allowing LACKMEM() to become true unexpectedly could still result in less-than-desirable behavior, so let's patch it all the way back.
Diffstat (limited to 'src/backend/utils/sort/tuplesort.c')
-rw-r--r--src/backend/utils/sort/tuplesort.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c
index 1e62a73eed3..d532e87450e 100644
--- a/src/backend/utils/sort/tuplesort.c
+++ b/src/backend/utils/sort/tuplesort.c
@@ -577,7 +577,14 @@ tuplesort_begin_common(int workMem, bool randomAccess)
state->tapeset = NULL;
state->memtupcount = 0;
- state->memtupsize = 1024; /* initial guess */
+
+ /*
+ * Initial size of array must be more than ALLOCSET_SEPARATE_THRESHOLD;
+ * see comments in grow_memtuples().
+ */
+ state->memtupsize = Max(1024,
+ ALLOCSET_SEPARATE_THRESHOLD / sizeof(SortTuple) + 1);
+
state->growmemtuples = true;
state->memtuples = (SortTuple *) palloc(state->memtupsize * sizeof(SortTuple));
@@ -1165,10 +1172,10 @@ grow_memtuples(Tuplesortstate *state)
* never generate a dangerous request, but to be safe, check explicitly
* that the array growth fits within availMem. (We could still cause
* LACKMEM if the memory chunk overhead associated with the memtuples
- * array were to increase. That shouldn't happen with any sane value of
- * allowedMem, because at any array size large enough to risk LACKMEM,
- * palloc would be treating both old and new arrays as separate chunks.
- * But we'll check LACKMEM explicitly below just in case.)
+ * array were to increase. That shouldn't happen because we chose the
+ * initial array size large enough to ensure that palloc will be treating
+ * both old and new arrays as separate chunks. But we'll check LACKMEM
+ * explicitly below just in case.)
*/
if (state->availMem < (int64) ((newmemtupsize - memtupsize) * sizeof(SortTuple)))
goto noalloc;
@@ -1181,7 +1188,7 @@ grow_memtuples(Tuplesortstate *state)
state->memtupsize * sizeof(SortTuple));
USEMEM(state, GetMemoryChunkSpace(state->memtuples));
if (LACKMEM(state))
- elog(ERROR, "unexpected out-of-memory situation during sort");
+ elog(ERROR, "unexpected out-of-memory situation in tuplesort");
return true;
noalloc: