On Tue, Jan 27, 2015 at 5:34 PM, Andres Freund <[email protected]> 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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers