summaryrefslogtreecommitdiff
path: root/src/backend/utils/mmgr
diff options
context:
space:
mode:
authorNoah Misch <noah@leadboat.com>2013-06-27 14:53:57 -0400
committerNoah Misch <noah@leadboat.com>2013-06-27 14:53:57 -0400
commit263865a48973767ce8ed7b7788059a38a24a9f37 (patch)
tree282d6522ada24adc923ea869c01b9d94f02685db /src/backend/utils/mmgr
parent9ef86cd994e9f2a684996df994d4657e84a6c0bb (diff)
downloadpostgresql-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.c5
-rw-r--r--src/backend/utils/mmgr/mcxt.c74
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
*/