On Tue, Jan 27, 2015 at 5:34 PM, Andres Freund <and...@2ndquadrant.com> wrote: > On 2015-01-27 17:27:53 +0900, Michael Paquier wrote: >> Alvaro Herrera wrote: >> >> So how about something like >> >> >> >> #define ALLOCFLAG_HUGE 0x01 >> >> #define ALLOCFLAG_NO_ERROR_ON_OOM 0x02 >> >> void * >> >> MemoryContextAllocFlags(MemoryContext context, Size size, int flags); >> The flag for huge allocations may be useful, but I don't actually see >> much value in the flag ALLOC_NO_OOM if the stuff in aset.c returns >> unconditionally NULL in case of an OOM and we let palloc complain >> about an OOM when allocation returns NULL. Something I am missing >> perhaps? > > I guess the idea is to have *user facing* MemoryContextAllocExtended() > that can do both huge and no-oom allocations. Otherwise we need palloc > like wrappers for all combinations. > We're certainly not just going to ignore memory allocation failures > generally in in MemoryContextAllocExtended().... As a result of all the comments on this thread, here are 3 patches implementing incrementally the different ideas from everybody: 1) 0001 modifies aset.c to return unconditionally NULL in case of an OOM instead of reporting an error. All the OOM error reports are moved to mcxt.c (MemoryContextAlloc* and palloc*) 2) 0002 adds the noerror routines for frontend and backend. 3) 0003 adds MemoryContextAllocExtended that can be called with the following control flags: #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 */ This groups MemoryContextAlloc, MemoryContextAllocHuge, MemoryContextAllocZero and MemoryContextAllocZeroAligned under the same central routine. Regards, -- Michael
From 337c439554ce66486cf9d29dced6c72d034b8f8d Mon Sep 17 00:00:00 2001 From: Michael Paquier <mich...@otacoo.com> Date: Wed, 28 Jan 2015 22:10:13 +0900 Subject: [PATCH 1/3] Make allocation return functions return NULL on OOM
On counterpart, higher-level APIs in mcxt.c return an explicit error message when memory requests cannot be completed. --- src/backend/utils/mmgr/aset.c | 30 ++++++++++++--------------- src/backend/utils/mmgr/mcxt.c | 48 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 17 deletions(-) diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c index 85b3c9a..bf6f09a 100644 --- a/src/backend/utils/mmgr/aset.c +++ b/src/backend/utils/mmgr/aset.c @@ -642,8 +642,8 @@ AllocSetDelete(MemoryContext context) /* * AllocSetAlloc - * Returns pointer to allocated memory of given size; memory is added - * to the set. + * Returns pointer to allocated memory of given size or NULL if + * request could not be completed; memory is added to the set. * * No request may exceed: * MAXALIGN_DOWN(SIZE_MAX) - ALLOC_BLOCKHDRSZ - ALLOC_CHUNKHDRSZ @@ -673,10 +673,7 @@ AllocSetAlloc(MemoryContext context, Size size) if (block == NULL) { MemoryContextStats(TopMemoryContext); - ereport(ERROR, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"), - errdetail("Failed on request of size %zu.", size))); + return NULL; } block->aset = set; block->freeptr = block->endptr = ((char *) block) + blksize; @@ -867,10 +864,7 @@ AllocSetAlloc(MemoryContext context, Size size) if (block == NULL) { MemoryContextStats(TopMemoryContext); - ereport(ERROR, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"), - errdetail("Failed on request of size %zu.", size))); + return NULL; } block->aset = set; @@ -1002,9 +996,10 @@ AllocSetFree(MemoryContext context, void *pointer) /* * AllocSetRealloc - * Returns new pointer to allocated memory of given size; this memory - * is added to the set. Memory associated with given pointer is copied - * into the new memory, and the old memory is freed. + * Returns new pointer to allocated memory of given size or NULL if + * request could not be completed; this memory is added to the set. + * Memory associated with given pointer is copied into the new memory, + * and the old memory is freed. * * Without MEMORY_CONTEXT_CHECKING, we don't know the old request size. This * makes our Valgrind client requests less-precise, hazarding false negatives. @@ -1109,10 +1104,7 @@ AllocSetRealloc(MemoryContext context, void *pointer, Size size) if (block == NULL) { MemoryContextStats(TopMemoryContext); - ereport(ERROR, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"), - errdetail("Failed on request of size %zu.", size))); + return NULL; } block->freeptr = block->endptr = ((char *) block) + blksize; @@ -1179,6 +1171,10 @@ AllocSetRealloc(MemoryContext context, void *pointer, Size size) /* allocate new chunk */ newPointer = AllocSetAlloc((MemoryContext) set, size); + /* leave immediately if request was not completed */ + if (newPointer == NULL) + return NULL; + /* * AllocSetAlloc() just made the region NOACCESS. Change it to * UNDEFINED for the moment; memcpy() will then transfer definedness diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c index aa0d458..f6cf0cc 100644 --- a/src/backend/utils/mmgr/mcxt.c +++ b/src/backend/utils/mmgr/mcxt.c @@ -623,6 +623,12 @@ MemoryContextAlloc(MemoryContext context, Size 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; @@ -649,6 +655,12 @@ MemoryContextAllocZero(MemoryContext context, Size 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); @@ -677,6 +689,12 @@ MemoryContextAllocZeroAligned(MemoryContext context, Size 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); @@ -699,6 +717,12 @@ palloc(Size size) CurrentMemoryContext->isReset = false; ret = (*CurrentMemoryContext->methods->alloc) (CurrentMemoryContext, 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(CurrentMemoryContext, ret, size); return ret; @@ -719,6 +743,12 @@ palloc0(Size size) CurrentMemoryContext->isReset = false; ret = (*CurrentMemoryContext->methods->alloc) (CurrentMemoryContext, 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(CurrentMemoryContext, ret, size); MemSetAligned(ret, 0, size); @@ -789,6 +819,12 @@ repalloc(void *pointer, Size size) Assert(!context->isReset); ret = (*context->methods->realloc) (context, pointer, 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_CHANGE(context, pointer, ret, size); return ret; @@ -814,6 +850,12 @@ MemoryContextAllocHuge(MemoryContext context, Size 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; @@ -854,6 +896,12 @@ repalloc_huge(void *pointer, Size size) Assert(!context->isReset); ret = (*context->methods->realloc) (context, pointer, 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_CHANGE(context, pointer, ret, size); return ret; -- 2.2.2
From 13a05f5b28ab00864a9d96fae5a72402cf43184b Mon Sep 17 00:00:00 2001 From: Michael Paquier <mich...@otacoo.com> Date: Wed, 28 Jan 2015 22:46:04 +0900 Subject: [PATCH 2/3] Add *_noerror routines for palloc memory allocation The following routines are added for frontend and backend: - palloc_noerror, equivalent of palloc but returning NULL if memory request could not be completed - palloc0_noerror, equivalent of palloc0 but returning NULL if memory request could not be completed - repalloc_noerror, equivalent of repalloc bur returning NULL if memory request could not be completed --- src/backend/utils/mmgr/mcxt.c | 129 ++++++++++++++++++++++++--------------- src/common/fe_memutils.c | 73 ++++++++++++++++------ src/include/common/fe_memutils.h | 3 + src/include/utils/palloc.h | 3 + 4 files changed, 140 insertions(+), 68 deletions(-) diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c index f6cf0cc..f8907a8 100644 --- a/src/backend/utils/mmgr/mcxt.c +++ b/src/backend/utils/mmgr/mcxt.c @@ -56,6 +56,10 @@ MemoryContext PortalContext = NULL; static void MemoryContextStatsInternal(MemoryContext context, int level); +/* wrapper routines for allocation */ +static inline void* palloc_internal(Size size, bool noerror); +static inline void* repalloc_internal(void *pointer, Size size, bool noerror); + /* * You should not do memory allocations within a critical section, because * an out-of-memory error will be escalated to a PANIC. To enforce that @@ -702,8 +706,8 @@ MemoryContextAllocZeroAligned(MemoryContext context, Size size) return ret; } -void * -palloc(Size size) +static inline void * +palloc_internal(Size size, bool noerror) { /* duplicates MemoryContextAlloc to avoid increased overhead */ void *ret; @@ -717,42 +721,90 @@ palloc(Size size) CurrentMemoryContext->isReset = false; ret = (*CurrentMemoryContext->methods->alloc) (CurrentMemoryContext, size); - if (ret == NULL) + if (!noerror && ret == NULL) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"), errdetail("Failed on request of size %zu.", size))); - VALGRIND_MEMPOOL_ALLOC(CurrentMemoryContext, ret, size); + if (ret != NULL) + VALGRIND_MEMPOOL_ALLOC(CurrentMemoryContext, ret, size); return ret; } -void * -palloc0(Size size) +static inline void * +repalloc_internal(void *pointer, Size size, bool noerror) { - /* duplicates MemoryContextAllocZero to avoid increased overhead */ + MemoryContext context; void *ret; - AssertArg(MemoryContextIsValid(CurrentMemoryContext)); - AssertNotInCriticalSection(CurrentMemoryContext); - if (!AllocSizeIsValid(size)) elog(ERROR, "invalid memory alloc request size %zu", size); - CurrentMemoryContext->isReset = false; + /* + * Try to detect bogus pointers handed to us, poorly though we can. + * Presumably, a pointer that isn't MAXALIGNED isn't pointing at an + * allocated chunk. + */ + Assert(pointer != NULL); + Assert(pointer == (void *) MAXALIGN(pointer)); - ret = (*CurrentMemoryContext->methods->alloc) (CurrentMemoryContext, size); - if (ret == NULL) + /* + * OK, it's probably safe to look at the chunk header. + */ + context = ((StandardChunkHeader *) + ((char *) pointer - STANDARDCHUNKHEADERSIZE))->context; + + AssertArg(MemoryContextIsValid(context)); + AssertNotInCriticalSection(context); + + /* isReset must be false already */ + Assert(!context->isReset); + + ret = (*context->methods->realloc) (context, pointer, size); + if (!noerror && ret == NULL) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"), errdetail("Failed on request of size %zu.", size))); - VALGRIND_MEMPOOL_ALLOC(CurrentMemoryContext, ret, size); + if (ret != NULL) + VALGRIND_MEMPOOL_CHANGE(context, pointer, ret, size); + + return ret; + +} + +void * +palloc(Size size) +{ + return palloc_internal(size, false); +} + +void * +palloc_noerror(Size size) +{ + return palloc_internal(size, true); +} + +void * +palloc0(Size size) +{ + void *ret; + ret = palloc_internal(size, false); MemSetAligned(ret, 0, size); + return ret; +} +void * +palloc0_noerror(Size size) +{ + void *ret; + + ret = palloc_internal(size, true); + MemSetAligned(ret, 0, size); return ret; } @@ -787,47 +839,24 @@ pfree(void *pointer) /* * repalloc - * Adjust the size of a previously allocated chunk. + * Adjust the size of a previously allocated chunk, failing if + * request could not be completed. */ void * repalloc(void *pointer, Size size) { - MemoryContext context; - void *ret; - - if (!AllocSizeIsValid(size)) - elog(ERROR, "invalid memory alloc request size %zu", size); - - /* - * Try to detect bogus pointers handed to us, poorly though we can. - * Presumably, a pointer that isn't MAXALIGNED isn't pointing at an - * allocated chunk. - */ - Assert(pointer != NULL); - Assert(pointer == (void *) MAXALIGN(pointer)); - - /* - * OK, it's probably safe to look at the chunk header. - */ - context = ((StandardChunkHeader *) - ((char *) pointer - STANDARDCHUNKHEADERSIZE))->context; - - AssertArg(MemoryContextIsValid(context)); - AssertNotInCriticalSection(context); - - /* isReset must be false already */ - Assert(!context->isReset); - - ret = (*context->methods->realloc) (context, pointer, 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_CHANGE(context, pointer, ret, size); + return repalloc_internal(pointer, size, false); +} - return ret; +/* + * repalloc_noerror + * Adjust the size of a previously allocated chunk, returning NULL + * if request could not be completed. + */ +void * +repalloc_noerror(void *pointer, Size size) +{ + return repalloc_internal(pointer, size, true); } /* diff --git a/src/common/fe_memutils.c b/src/common/fe_memutils.c index 345221e..9a312c4 100644 --- a/src/common/fe_memutils.c +++ b/src/common/fe_memutils.c @@ -19,8 +19,8 @@ #include "postgres_fe.h" -void * -pg_malloc(size_t size) +static inline void * +pg_malloc_internal(size_t size, bool noerror) { void *tmp; @@ -28,7 +28,24 @@ pg_malloc(size_t size) if (size == 0) size = 1; tmp = malloc(size); - if (!tmp) + if (!tmp && !noerror) + { + fprintf(stderr, _("out of memory\n")); + exit(EXIT_FAILURE); + } + return tmp; +} + +static inline void * +pg_realloc_internal(void *ptr, size_t size, bool noerror) +{ + void *tmp; + + /* Avoid unportable behavior of realloc(NULL, 0) */ + if (ptr == NULL && size == 0) + size = 1; + tmp = realloc(ptr, size); + if (!tmp && !noerror) { fprintf(stderr, _("out of memory\n")); exit(EXIT_FAILURE); @@ -37,6 +54,12 @@ pg_malloc(size_t size) } void * +pg_malloc(size_t size) +{ + return pg_malloc_internal(size, false); +} + +void * pg_malloc0(size_t size) { void *tmp; @@ -49,20 +72,10 @@ pg_malloc0(size_t size) void * pg_realloc(void *ptr, size_t size) { - void *tmp; - - /* Avoid unportable behavior of realloc(NULL, 0) */ - if (ptr == NULL && size == 0) - size = 1; - tmp = realloc(ptr, size); - if (!tmp) - { - fprintf(stderr, _("out of memory\n")); - exit(EXIT_FAILURE); - } - return tmp; + return pg_realloc_internal(ptr, size, false); } + /* * "Safe" wrapper around strdup(). */ @@ -100,13 +113,31 @@ pg_free(void *ptr) void * palloc(Size size) { - return pg_malloc(size); + return pg_malloc_internal(size, false); +} + +void * +palloc_noerror(Size size) +{ + return pg_malloc_internal(size, true); } void * palloc0(Size size) { - return pg_malloc0(size); + void *tmp; + tmp = pg_malloc_internal(size, false); + MemSet(tmp, 0, size); + return tmp; +} + +void * +palloc0_noerror(Size size) +{ + void *tmp; + tmp = pg_malloc_internal(size, true); + MemSet(tmp, 0, size); + return tmp; } void @@ -124,5 +155,11 @@ pstrdup(const char *in) void * repalloc(void *pointer, Size size) { - return pg_realloc(pointer, size); + return pg_realloc_internal(pointer, size, false); +} + +void * +repalloc_noerror(void *pointer, Size size) +{ + return pg_realloc_internal(pointer, size, true); } diff --git a/src/include/common/fe_memutils.h b/src/include/common/fe_memutils.h index f7114c2..0151e6e 100644 --- a/src/include/common/fe_memutils.h +++ b/src/include/common/fe_memutils.h @@ -19,8 +19,11 @@ extern void pg_free(void *pointer); /* Equivalent functions, deliberately named the same as backend functions */ extern char *pstrdup(const char *in); extern void *palloc(Size size); +extern void *palloc_noerror(Size size); extern void *palloc0(Size size); +extern void *palloc0_noerror(Size size); extern void *repalloc(void *pointer, Size size); +extern void *repalloc_noerror(void *pointer, Size size); extern void pfree(void *pointer); /* sprintf into a palloc'd buffer --- these are in psprintf.c */ diff --git a/src/include/utils/palloc.h b/src/include/utils/palloc.h index ca03f2b..3634a7f 100644 --- a/src/include/utils/palloc.h +++ b/src/include/utils/palloc.h @@ -50,8 +50,11 @@ extern void *MemoryContextAllocZero(MemoryContext context, Size size); extern void *MemoryContextAllocZeroAligned(MemoryContext context, Size size); extern void *palloc(Size size); +extern void *palloc_noerror(Size size); extern void *palloc0(Size size); +extern void *palloc0_noerror(Size size); extern void *repalloc(void *pointer, Size size); +extern void *repalloc_noerror(void *pointer, Size size); extern void pfree(void *pointer); /* -- 2.2.2
From 1ff0406b11a6e54cdb0a4312c199dbe7800fea82 Mon Sep 17 00:00:00 2001 From: Michael Paquier <mich...@otacoo.com> 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
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers