From 1ff0406b11a6e54cdb0a4312c199dbe7800fea82 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Wed, 28 Jan 2015 23:27:54 +0900 Subject: [PATCH 3/3] Create MemoryContextAllocExtended central routine for memory allocation This new routine is the central point of all the MemoryContextAlloc* functions controlled by a set of flags allowing a far wider control of how allocation can be done in a memory context. --- src/backend/utils/mmgr/mcxt.c | 107 ++++++++++++------------------------------ src/include/utils/palloc.h | 11 +++++ 2 files changed, 41 insertions(+), 77 deletions(-) diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c index f8907a8..01201fb 100644 --- a/src/backend/utils/mmgr/mcxt.c +++ b/src/backend/utils/mmgr/mcxt.c @@ -607,21 +607,20 @@ MemoryContextCreate(NodeTag tag, Size size, } /* - * MemoryContextAlloc - * Allocate space within the specified context. - * - * This could be turned into a macro, but we'd have to import - * nodes/memnodes.h into postgres.h which seems a bad idea. + * MemoryContextAllocExtended + * Allocation space within the specified context using flag options + * specified by caller. */ void * -MemoryContextAlloc(MemoryContext context, Size size) +MemoryContextAllocExtended(MemoryContext context, Size size, int flags) { void *ret; AssertArg(MemoryContextIsValid(context)); AssertNotInCriticalSection(context); - if (!AllocSizeIsValid(size)) + if (((flags & ALLOC_HUGE) != 0 && !AllocHugeSizeIsValid(size)) || + !AllocSizeIsValid(size)) elog(ERROR, "invalid memory alloc request size %zu", size); context->isReset = false; @@ -635,75 +634,48 @@ MemoryContextAlloc(MemoryContext context, Size size) VALGRIND_MEMPOOL_ALLOC(context, ret, size); + /* + * MemSetAligned and MemSetLoop should not be called in parallel + * (see c.h for more details). + */ + Assert((flags & ALLOC_ALIGNED) == 0 || (flags & ALLOC_HUGE) == 0); + + if ((flags & ALLOC_ZERO) != 0) + MemSetAligned(ret, 0, size); + if ((flags & ALLOC_ALIGNED) != 0) + MemSetLoop(ret, 0, size); + return ret; } /* + * MemoryContextAlloc + * Allocate space within the specified context. + */ +void * +MemoryContextAlloc(MemoryContext context, Size size) +{ + return MemoryContextAllocExtended(context, size, 0); +} + +/* * MemoryContextAllocZero * Like MemoryContextAlloc, but clears allocated memory - * - * We could just call MemoryContextAlloc then clear the memory, but this - * is a very common combination, so we provide the combined operation. */ void * MemoryContextAllocZero(MemoryContext context, Size size) { - void *ret; - - AssertArg(MemoryContextIsValid(context)); - AssertNotInCriticalSection(context); - - if (!AllocSizeIsValid(size)) - elog(ERROR, "invalid memory alloc request size %zu", size); - - context->isReset = false; - - ret = (*context->methods->alloc) (context, size); - if (ret == NULL) - ereport(ERROR, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"), - errdetail("Failed on request of size %zu.", size))); - - VALGRIND_MEMPOOL_ALLOC(context, ret, size); - - MemSetAligned(ret, 0, size); - - return ret; + return MemoryContextAllocExtended(context, size, ALLOC_ZERO); } /* * MemoryContextAllocZeroAligned * MemoryContextAllocZero where length is suitable for MemSetLoop - * - * This might seem overly specialized, but it's not because newNode() - * is so often called with compile-time-constant sizes. */ void * MemoryContextAllocZeroAligned(MemoryContext context, Size size) { - void *ret; - - AssertArg(MemoryContextIsValid(context)); - AssertNotInCriticalSection(context); - - if (!AllocSizeIsValid(size)) - elog(ERROR, "invalid memory alloc request size %zu", size); - - context->isReset = false; - - ret = (*context->methods->alloc) (context, size); - if (ret == NULL) - ereport(ERROR, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"), - errdetail("Failed on request of size %zu.", size))); - - VALGRIND_MEMPOOL_ALLOC(context, ret, size); - - MemSetLoop(ret, 0, size); - - return ret; + return MemoryContextAllocExtended(context, size, ALLOC_ALIGNED); } static inline void * @@ -868,26 +840,7 @@ repalloc_noerror(void *pointer, Size size) void * MemoryContextAllocHuge(MemoryContext context, Size size) { - void *ret; - - AssertArg(MemoryContextIsValid(context)); - AssertNotInCriticalSection(context); - - if (!AllocHugeSizeIsValid(size)) - elog(ERROR, "invalid memory alloc request size %zu", size); - - context->isReset = false; - - ret = (*context->methods->alloc) (context, size); - if (ret == NULL) - ereport(ERROR, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"), - errdetail("Failed on request of size %zu.", size))); - - VALGRIND_MEMPOOL_ALLOC(context, ret, size); - - return ret; + return MemoryContextAllocExtended(context, size, ALLOC_HUGE); } /* diff --git a/src/include/utils/palloc.h b/src/include/utils/palloc.h index 3634a7f..a8bf9a1 100644 --- a/src/include/utils/palloc.h +++ b/src/include/utils/palloc.h @@ -43,8 +43,19 @@ typedef struct MemoryContextData *MemoryContext; extern PGDLLIMPORT MemoryContext CurrentMemoryContext; /* + * Additional options for MemoryContextAllocExtended() + */ +#define ALLOC_HUGE 0x01 /* huge allocation */ +#define ALLOC_ZERO 0x02 /* clear allocated memory */ +#define ALLOC_NO_OOM 0x04 /* no failure if out-of-memory */ +#define ALLOC_ALIGNED 0x08 /* request length suitable for MemSetLoop */ + +/* * Fundamental memory-allocation operations (more are in utils/memutils.h) */ +extern void *MemoryContextAllocExtended(MemoryContext context, + Size size, + int flags); extern void *MemoryContextAlloc(MemoryContext context, Size size); extern void *MemoryContextAllocZero(MemoryContext context, Size size); extern void *MemoryContextAllocZeroAligned(MemoryContext context, Size size); -- 2.2.2