diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c index 743455e4bcc219e9b357c24326a9311bc9d96c0d..9dfdc2e87e094179fb938fbb59653dd82f40bb3a 100644 --- a/src/backend/utils/mmgr/aset.c +++ b/src/backend/utils/mmgr/aset.c @@ -112,9 +112,9 @@ * * With the current parameters, request sizes up to 8K are treated as chunks, * larger requests go into dedicated blocks. Change ALLOCSET_NUM_FREELISTS - * to adjust the boundary point. (But in contexts with small maxBlockSize, - * we may set the allocChunkLimit to less than 8K, so as to avoid space - * wastage.) + * to adjust the boundary point; and adjust ALLOCSET_SEPARATE_THRESHOLD in + * memutils.h to agree. (Note: in contexts with small maxBlockSize, we may + * set the allocChunkLimit to less than 8K, so as to avoid space wastage.) *-------------------- */ @@ -476,7 +476,12 @@ AllocSetContextCreate(MemoryContext parent, * We have to have allocChunkLimit a power of two, because the requested * and actually-allocated sizes of any chunk must be on the same side of * the limit, else we get confused about whether the chunk is "big". + * + * Also, allocChunkLimit must not exceed ALLOCSET_SEPARATE_THRESHOLD. */ + StaticAssertStmt(ALLOC_CHUNK_LIMIT == ALLOCSET_SEPARATE_THRESHOLD, + "ALLOC_CHUNK_LIMIT != ALLOCSET_SEPARATE_THRESHOLD"); + context->allocChunkLimit = ALLOC_CHUNK_LIMIT; while ((Size) (context->allocChunkLimit + ALLOC_CHUNKHDRSZ) > (Size) ((maxBlockSize - ALLOC_BLOCKHDRSZ) / ALLOC_CHUNK_FRACTION)) diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c index e78a51fe2283bdebf9e0de40f833bef6a61a1614..18cb046f19876737c52d8269692a67cd013eed99 100644 --- a/src/backend/utils/sort/tuplesort.c +++ b/src/backend/utils/sort/tuplesort.c @@ -571,7 +571,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)); @@ -1064,10 +1071,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; @@ -1080,7 +1087,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: diff --git a/src/backend/utils/sort/tuplestore.c b/src/backend/utils/sort/tuplestore.c index 1d6fe869944d90bbca7db424bc788377b355bd41..c5f7f3d01dbe2e31f77e0ffdae026fffdd541989 100644 --- a/src/backend/utils/sort/tuplestore.c +++ b/src/backend/utils/sort/tuplestore.c @@ -265,7 +265,14 @@ tuplestore_begin_common(int eflags, bool interXact, int maxKBytes) state->memtupdeleted = 0; 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(16384 / sizeof(void *), + ALLOCSET_SEPARATE_THRESHOLD / sizeof(void *) + 1); + state->growmemtuples = true; state->memtuples = (void **) palloc(state->memtupsize * sizeof(void *)); @@ -639,10 +646,10 @@ grow_memtuples(Tuplestorestate *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(void *))) goto noalloc; @@ -655,7 +662,7 @@ grow_memtuples(Tuplestorestate *state) state->memtupsize * sizeof(void *)); 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 tuplestore"); return true; noalloc: diff --git a/src/include/utils/memutils.h b/src/include/utils/memutils.h index 59d0aecfbbcd62aaa0c1b19962422b45e63783e2..9f499d118042cd33e97af09a9022c47539cc6bb1 100644 --- a/src/include/utils/memutils.h +++ b/src/include/utils/memutils.h @@ -145,4 +145,12 @@ extern MemoryContext AllocSetContextCreate(MemoryContext parent, #define ALLOCSET_SMALL_INITSIZE (1 * 1024) #define ALLOCSET_SMALL_MAXSIZE (8 * 1024) +/* + * Threshold above which a request in an AllocSet context is certain to be + * allocated separately (and thereby have constant allocation overhead). + * Few callers should be interested in this, but tuplesort/tuplestore need + * to know it. + */ +#define ALLOCSET_SEPARATE_THRESHOLD 8192 + #endif /* MEMUTILS_H */