diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c index 49e15d40802..c7cbd2b6657 100644 --- a/src/backend/utils/mmgr/aset.c +++ b/src/backend/utils/mmgr/aset.c @@ -353,6 +353,45 @@ AllocSetFreeIndex(Size size) return idx; } +/* ---------- + * AllocSetFreeIndex - + * + * Compute and return the multi-chunk block chunk size limit for the + * given maximum block size. + * ---------- + */ +static inline uint32 +AllocSetComputeChunkLimit(Size maxBlockSize) +{ + uint32 allocChunkLimit; + + /* + * Compute the allocation chunk size limit for this context. It can't be + * more than ALLOC_CHUNK_LIMIT because of the fixed number of freelists. + * If maxBlockSize is small then requests exceeding the maxBlockSize, or + * even a significant fraction of it, should be treated as large chunks + * too. For the typical case of maxBlockSize a power of 2, the chunk size + * limit will be at most 1/8th maxBlockSize, so that given a stream of + * requests that are all the maximum chunk size we will waste at most + * 1/8th of the allocated space. + * + * 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"); + + allocChunkLimit = ALLOC_CHUNK_LIMIT; + while ((Size) (allocChunkLimit + ALLOC_CHUNKHDRSZ) > + (Size) ((maxBlockSize - ALLOC_BLOCKHDRSZ) / ALLOC_CHUNK_FRACTION)) + allocChunkLimit >>= 1; + + return allocChunkLimit; +} + /* * Public routines @@ -437,8 +476,18 @@ AllocSetContextCreateInternal(MemoryContext parent, freelist->first_free = (AllocSet) set->header.nextchild; freelist->num_free--; - /* Update its maxBlockSize; everything else should be OK */ - set->maxBlockSize = maxBlockSize; + /* nextBlockSize should have been reset in AllocSetReset() */ + Assert(set->nextBlockSize == set->initBlockSize); + + if (set->maxBlockSize != maxBlockSize) + { + /* + * Update its maxBlockSize and allocChunkLimit; everything + * else should be OK. + */ + set->maxBlockSize = maxBlockSize; + set->allocChunkLimit = AllocSetComputeChunkLimit(maxBlockSize); + } /* Reinitialize its header, installing correct name and parent */ MemoryContextCreate((MemoryContext) set, @@ -507,29 +556,7 @@ AllocSetContextCreateInternal(MemoryContext parent, set->nextBlockSize = initBlockSize; set->freeListIndex = freeListIndex; - /* - * Compute the allocation chunk size limit for this context. It can't be - * more than ALLOC_CHUNK_LIMIT because of the fixed number of freelists. - * If maxBlockSize is small then requests exceeding the maxBlockSize, or - * even a significant fraction of it, should be treated as large chunks - * too. For the typical case of maxBlockSize a power of 2, the chunk size - * limit will be at most 1/8th maxBlockSize, so that given a stream of - * requests that are all the maximum chunk size we will waste at most - * 1/8th of the allocated space. - * - * 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"); - - set->allocChunkLimit = ALLOC_CHUNK_LIMIT; - while ((Size) (set->allocChunkLimit + ALLOC_CHUNKHDRSZ) > - (Size) ((maxBlockSize - ALLOC_BLOCKHDRSZ) / ALLOC_CHUNK_FRACTION)) - set->allocChunkLimit >>= 1; + set->allocChunkLimit = AllocSetComputeChunkLimit(maxBlockSize); /* Finally, do the type-independent part of context creation */ MemoryContextCreate((MemoryContext) set,