diff options
author | Noah Misch <noah@leadboat.com> | 2013-06-27 14:53:57 -0400 |
---|---|---|
committer | Noah Misch <noah@leadboat.com> | 2013-06-27 14:53:57 -0400 |
commit | 263865a48973767ce8ed7b7788059a38a24a9f37 (patch) | |
tree | 282d6522ada24adc923ea869c01b9d94f02685db /src/backend/utils/mmgr | |
parent | 9ef86cd994e9f2a684996df994d4657e84a6c0bb (diff) | |
download | postgresql-263865a48973767ce8ed7b7788059a38a24a9f37.tar.gz |
Permit super-MaxAllocSize allocations with MemoryContextAllocHuge().
The MaxAllocSize guard is convenient for most callers, because it
reduces the need for careful attention to overflow, data type selection,
and the SET_VARSIZE() limit. A handful of callers are happy to navigate
those hazards in exchange for the ability to allocate a larger chunk.
Introduce MemoryContextAllocHuge() and repalloc_huge(). Use this in
tuplesort.c and tuplestore.c, enabling internal sorts of up to INT_MAX
tuples, a factor-of-48 increase. In particular, B-tree index builds can
now benefit from much-larger maintenance_work_mem settings.
Reviewed by Stephen Frost, Simon Riggs and Jeff Janes.
Diffstat (limited to 'src/backend/utils/mmgr')
-rw-r--r-- | src/backend/utils/mmgr/aset.c | 5 | ||||
-rw-r--r-- | src/backend/utils/mmgr/mcxt.c | 74 |
2 files changed, 71 insertions, 8 deletions
diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c index ab93620ae2..ff04a38cda 100644 --- a/src/backend/utils/mmgr/aset.c +++ b/src/backend/utils/mmgr/aset.c @@ -458,6 +458,7 @@ AllocSetContextCreate(MemoryContext parent, maxBlockSize = MAXALIGN(maxBlockSize); if (maxBlockSize < initBlockSize) maxBlockSize = initBlockSize; + Assert(AllocHugeSizeIsValid(maxBlockSize)); /* must be safe to double */ context->initBlockSize = initBlockSize; context->maxBlockSize = maxBlockSize; context->nextBlockSize = initBlockSize; @@ -643,6 +644,10 @@ AllocSetDelete(MemoryContext context) * AllocSetAlloc * Returns pointer to allocated memory of given size; memory is added * to the set. + * + * No request may exceed: + * MAXALIGN_DOWN(SIZE_MAX) - ALLOC_BLOCKHDRSZ - ALLOC_CHUNKHDRSZ + * All callers use a much-lower limit. */ static void * AllocSetAlloc(MemoryContext context, Size size) diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c index 46961e9ee9..9574fd3c7a 100644 --- a/src/backend/utils/mmgr/mcxt.c +++ b/src/backend/utils/mmgr/mcxt.c @@ -455,14 +455,7 @@ MemoryContextContains(MemoryContext context, void *pointer) header = (StandardChunkHeader *) ((char *) pointer - STANDARDCHUNKHEADERSIZE); - /* - * If the context link doesn't match then we certainly have a non-member - * chunk. Also check for a reasonable-looking size as extra guard against - * being fooled by bogus pointers. - */ - if (header->context == context && AllocSizeIsValid(header->size)) - return true; - return false; + return header->context == context; } /*-------------------- @@ -758,6 +751,71 @@ repalloc(void *pointer, Size size) } /* + * MemoryContextAllocHuge + * Allocate (possibly-expansive) space within the specified context. + * + * See considerations in comment at MaxAllocHugeSize. + */ +void * +MemoryContextAllocHuge(MemoryContext context, Size size) +{ + void *ret; + + AssertArg(MemoryContextIsValid(context)); + + if (!AllocHugeSizeIsValid(size)) + elog(ERROR, "invalid memory alloc request size %lu", + (unsigned long) size); + + context->isReset = false; + + ret = (*context->methods->alloc) (context, size); + VALGRIND_MEMPOOL_ALLOC(context, ret, size); + + return ret; +} + +/* + * repalloc_huge + * Adjust the size of a previously allocated chunk, permitting a large + * value. The previous allocation need not have been "huge". + */ +void * +repalloc_huge(void *pointer, Size size) +{ + MemoryContext context; + void *ret; + + if (!AllocHugeSizeIsValid(size)) + elog(ERROR, "invalid memory alloc request size %lu", + (unsigned long) 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)); + + /* isReset must be false already */ + Assert(!context->isReset); + + ret = (*context->methods->realloc) (context, pointer, size); + VALGRIND_MEMPOOL_CHANGE(context, pointer, ret, size); + + return ret; +} + +/* * MemoryContextStrdup * Like strdup(), but allocate from the specified context */ |