From: Tomas Vondra Date: Fri, 30 Jul 2021 23:53:52 +0200 Subject: [PATCH 2/4] Generation: grow blocks --- contrib/generation_bench/generation_bench.c | 6 +-- src/backend/access/gist/gistvacuum.c | 2 +- .../replication/logical/reorderbuffer.c | 2 +- src/backend/utils/mmgr/generation.c | 53 ++++++++++++++----- src/include/utils/memutils.h | 4 +- 5 files changed, 47 insertions(+), 20 deletions(-) diff --git a/contrib/generation_bench/generation_bench.c b/contrib/generation_bench/generation_bench.c index f86aaaa041..bb058a7f1d 100644 --- a/contrib/generation_bench/generation_bench.c +++ b/contrib/generation_bench/generation_bench.c @@ -91,7 +91,7 @@ generation_bench_random(PG_FUNCTION_ARGS) maxchunks = nallocs + nloops * Max(0, alloc_cnt - free_cnt); - cxt = GenerationContextCreate(CurrentMemoryContext, "generation_bench", blockSize); + cxt = GenerationContextCreate(CurrentMemoryContext, "generation_bench", blockSize, blockSize, 1024L * 1024L); chunks = (Chunk *) palloc(maxchunks * sizeof(Chunk)); @@ -229,7 +229,7 @@ generation_bench_fifo(PG_FUNCTION_ARGS) maxchunks = nallocs + nloops * Max(0, alloc_cnt - free_cnt); - cxt = GenerationContextCreate(CurrentMemoryContext, "generation_bench", blockSize); + cxt = GenerationContextCreate(CurrentMemoryContext, "generation_bench", blockSize, blockSize, 1024L * 1024L); chunks = (Chunk *) palloc(maxchunks * sizeof(Chunk)); @@ -354,7 +354,7 @@ generation_bench_lifo(PG_FUNCTION_ARGS) maxchunks = nallocs + nloops * Max(0, alloc_cnt - free_cnt); - cxt = GenerationContextCreate(CurrentMemoryContext, "generation_bench", blockSize); + cxt = GenerationContextCreate(CurrentMemoryContext, "generation_bench", blockSize, blockSize, 1024L * 1024L); chunks = (Chunk *) palloc(maxchunks * sizeof(Chunk)); diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c index 0663193531..1818ed06fc 100644 --- a/src/backend/access/gist/gistvacuum.c +++ b/src/backend/access/gist/gistvacuum.c @@ -161,7 +161,7 @@ gistvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, */ vstate.page_set_context = GenerationContextCreate(CurrentMemoryContext, "GiST VACUUM page set context", - 16 * 1024); + ALLOCSET_DEFAULT_SIZES); oldctx = MemoryContextSwitchTo(vstate.page_set_context); vstate.internal_page_set = intset_create(); vstate.empty_leaf_set = intset_create(); diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c index 7378beb684..308d833292 100644 --- a/src/backend/replication/logical/reorderbuffer.c +++ b/src/backend/replication/logical/reorderbuffer.c @@ -329,7 +329,7 @@ ReorderBufferAllocate(void) buffer->tup_context = GenerationContextCreate(new_ctx, "Tuples", - SLAB_LARGE_BLOCK_SIZE); + ALLOCSET_DEFAULT_SIZES); hash_ctl.keysize = sizeof(TransactionId); hash_ctl.entrysize = sizeof(ReorderBufferTXNByIdEnt); diff --git a/src/backend/utils/mmgr/generation.c b/src/backend/utils/mmgr/generation.c index 584cd614da..771a2525ca 100644 --- a/src/backend/utils/mmgr/generation.c +++ b/src/backend/utils/mmgr/generation.c @@ -60,7 +60,9 @@ typedef struct GenerationContext MemoryContextData header; /* Standard memory-context fields */ /* Generational context parameters */ - Size blockSize; /* standard block size */ + Size initBlockSize; /* initial block size */ + Size maxBlockSize; /* maximum block size */ + Size nextBlockSize; /* next block size to allocate */ GenerationBlock *block; /* current (most recently allocated) block */ dlist_head blocks; /* list of blocks */ @@ -196,7 +198,9 @@ static const MemoryContextMethods GenerationMethods = { MemoryContext GenerationContextCreate(MemoryContext parent, const char *name, - Size blockSize) + Size minContextSize, + Size initBlockSize, + Size maxBlockSize) { GenerationContext *set; @@ -208,16 +212,20 @@ GenerationContextCreate(MemoryContext parent, "padding calculation in GenerationChunk is wrong"); /* - * First, validate allocation parameters. (If we're going to throw an - * error, we should do so before the context is created, not after.) We - * somewhat arbitrarily enforce a minimum 1K block size, mostly because - * that's what AllocSet does. + * First, validate allocation parameters. Once these were regular runtime + * test and elog's, but in practice Asserts seem sufficient because nobody + * varies their parameters at runtime. We somewhat arbitrarily enforce a + * minimum 1K block size. */ - if (blockSize != MAXALIGN(blockSize) || - blockSize < 1024 || - !AllocHugeSizeIsValid(blockSize)) - elog(ERROR, "invalid blockSize for memory context: %zu", - blockSize); + Assert(initBlockSize == MAXALIGN(initBlockSize) && + initBlockSize >= 1024); + Assert(maxBlockSize == MAXALIGN(maxBlockSize) && + maxBlockSize >= initBlockSize && + AllocHugeSizeIsValid(maxBlockSize)); /* must be safe to double */ + Assert(minContextSize == 0 || + (minContextSize == MAXALIGN(minContextSize) && + minContextSize >= 1024 && + minContextSize <= maxBlockSize)); /* * Allocate the context header. Unlike aset.c, we never try to combine @@ -242,7 +250,9 @@ GenerationContextCreate(MemoryContext parent, */ /* Fill in GenerationContext-specific header fields */ - set->blockSize = blockSize; + set->initBlockSize = initBlockSize; + set->maxBlockSize = maxBlockSize; + set->nextBlockSize = initBlockSize; set->block = NULL; dlist_init(&set->blocks); @@ -293,6 +303,9 @@ GenerationReset(MemoryContext context) set->block = NULL; + /* Reset block size allocation sequence, too */ + set->nextBlockSize = set->initBlockSize; + Assert(dlist_is_empty(&set->blocks)); } @@ -329,9 +342,12 @@ GenerationAlloc(MemoryContext context, Size size) GenerationBlock *block; GenerationChunk *chunk; Size chunk_size = MAXALIGN(size); + Size blockSize; + + blockSize = (set->block) ? set->block->blksize : set->nextBlockSize; /* is it an over-sized chunk? if yes, allocate special block */ - if (chunk_size > set->blockSize / 8) + if (chunk_size > (blockSize / 8)) { Size blksize = chunk_size + Generation_BLOCKHDRSZ + Generation_CHUNKHDRSZ; @@ -387,7 +403,16 @@ GenerationAlloc(MemoryContext context, Size size) if ((block == NULL) || (block->endptr - block->freeptr) < Generation_CHUNKHDRSZ + chunk_size) { - Size blksize = set->blockSize; + Size blksize; + + /* + * The first such block has size initBlockSize, and we double the + * space in each succeeding block, but not more than maxBlockSize. + */ + blksize = set->nextBlockSize; + set->nextBlockSize <<= 1; + if (set->nextBlockSize > set->maxBlockSize) + set->nextBlockSize = set->maxBlockSize; block = (GenerationBlock *) malloc(blksize); diff --git a/src/include/utils/memutils.h b/src/include/utils/memutils.h index ff872274d4..514c0bf75b 100644 --- a/src/include/utils/memutils.h +++ b/src/include/utils/memutils.h @@ -183,7 +183,9 @@ extern MemoryContext SlabContextCreate(MemoryContext parent, /* generation.c */ extern MemoryContext GenerationContextCreate(MemoryContext parent, const char *name, - Size blockSize); + Size minContextSize, + Size initBlockSize, + Size maxBlockSize); /* * Recommended default alloc parameters, suitable for "ordinary" contexts -- 2.31.1 --------------D082F723AC01DF154D86FBFF Content-Type: text/x-patch; charset=UTF-8; name="0003-Generation-keeper-block.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="0003-Generation-keeper-block.patch"