postgresql/src/backend/utils/mmgr/mcxt.c

696 lines
19 KiB
C
Raw Normal View History

/*-------------------------------------------------------------------------
*
* mcxt.c
* POSTGRES memory context management code.
*
* This module handles context management operations that are independent
* of the particular kind of context being operated on. It calls
* context-type-specific operations via the function pointers in a
* context's MemoryContextMethods struct.
*
*
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/mmgr/mcxt.c,v 1.59 2007/01/05 22:19:47 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "utils/memutils.h"
/*****************************************************************************
* GLOBAL MEMORY *
*****************************************************************************/
/*
1999-05-25 18:15:34 +02:00
* CurrentMemoryContext
* Default memory context for allocations.
*/
MemoryContext CurrentMemoryContext = NULL;
/*
This patch implements holdable cursors, following the proposal (materialization into a tuple store) discussed on pgsql-hackers earlier. I've updated the documentation and the regression tests. Notes on the implementation: - I needed to change the tuple store API slightly -- it assumes that it won't be used to hold data across transaction boundaries, so the temp files that it uses for on-disk storage are automatically reclaimed at end-of-transaction. I added a flag to tuplestore_begin_heap() to control this behavior. Is changing the tuple store API in this fashion OK? - in order to store executor results in a tuple store, I added a new CommandDest. This works well for the most part, with one exception: the current DestFunction API doesn't provide enough information to allow the Executor to store results into an arbitrary tuple store (where the particular tuple store to use is chosen by the call site of ExecutorRun). To workaround this, I've temporarily hacked up a solution that works, but is not ideal: since the receiveTuple DestFunction is passed the portal name, we can use that to lookup the Portal data structure for the cursor and then use that to get at the tuple store the Portal is using. This unnecessarily ties the Portal code with the tupleReceiver code, but it works... The proper fix for this is probably to change the DestFunction API -- Tom suggested passing the full QueryDesc to the receiveTuple function. In that case, callers of ExecutorRun could "subclass" QueryDesc to add any additional fields that their particular CommandDest needed to get access to. This approach would work, but I'd like to think about it for a little bit longer before deciding which route to go. In the mean time, the code works fine, so I don't think a fix is urgent. - (semi-related) I added a NO SCROLL keyword to DECLARE CURSOR, and adjusted the behavior of SCROLL in accordance with the discussion on -hackers. - (unrelated) Cleaned up some SGML markup in sql.sgml, copy.sgml Neil Conway
2003-03-27 17:51:29 +01:00
* Standard top-level contexts. For a description of the purpose of each
* of these contexts, refer to src/backend/utils/mmgr/README
*/
MemoryContext TopMemoryContext = NULL;
MemoryContext ErrorContext = NULL;
MemoryContext PostmasterContext = NULL;
MemoryContext CacheMemoryContext = NULL;
MemoryContext MessageContext = NULL;
MemoryContext TopTransactionContext = NULL;
MemoryContext CurTransactionContext = NULL;
2003-08-04 02:43:34 +02:00
/* These two are transient links to contexts owned by other objects: */
MemoryContext QueryContext = NULL;
MemoryContext PortalContext = NULL;
/*****************************************************************************
* EXPORTED ROUTINES *
*****************************************************************************/
/*
* MemoryContextInit
* Start up the memory-context subsystem.
*
* This must be called before creating contexts or allocating memory in
* contexts. TopMemoryContext and ErrorContext are initialized here;
* other contexts must be created afterwards.
*
* In normal multi-backend operation, this is called once during
* postmaster startup, and not at all by individual backend startup
* (since the backends inherit an already-initialized context subsystem
* by virtue of being forked off the postmaster).
*
* In a standalone backend this must be called during backend startup.
*/
void
MemoryContextInit(void)
{
AssertState(TopMemoryContext == NULL);
2001-03-22 05:01:46 +01:00
/*
2005-10-15 04:49:52 +02:00
* Initialize TopMemoryContext as an AllocSetContext with slow growth rate
* --- we don't really expect much to be allocated in it.
*
* (There is special-case code in MemoryContextCreate() for this call.)
*/
TopMemoryContext = AllocSetContextCreate((MemoryContext) NULL,
"TopMemoryContext",
0,
8 * 1024,
8 * 1024);
2001-03-22 05:01:46 +01:00
/*
2005-10-15 04:49:52 +02:00
* Not having any other place to point CurrentMemoryContext, make it point
* to TopMemoryContext. Caller should change this soon!
*/
CurrentMemoryContext = TopMemoryContext;
2001-03-22 05:01:46 +01:00
/*
2005-10-15 04:49:52 +02:00
* Initialize ErrorContext as an AllocSetContext with slow growth rate ---
* we don't really expect much to be allocated in it. More to the point,
* require it to contain at least 8K at all times. This is the only case
* where retained memory in a context is *essential* --- we want to be
* sure ErrorContext still has some memory even if we've run out
* elsewhere!
*/
ErrorContext = AllocSetContextCreate(TopMemoryContext,
"ErrorContext",
8 * 1024,
8 * 1024,
8 * 1024);
}
/*
* MemoryContextReset
* Release all space allocated within a context and its descendants,
* but don't delete the contexts themselves.
*
* The type-specific reset routine handles the context itself, but we
* have to do the recursion for the children.
*/
void
MemoryContextReset(MemoryContext context)
{
2000-08-22 06:00:10 +02:00
AssertArg(MemoryContextIsValid(context));
/* save a function call in common case where there are no children */
if (context->firstchild != NULL)
MemoryContextResetChildren(context);
(*context->methods->reset) (context);
}
/*
* MemoryContextResetChildren
* Release all space allocated within a context's descendants,
* but don't delete the contexts themselves. The named context
* itself is not touched.
*/
void
MemoryContextResetChildren(MemoryContext context)
{
2001-03-22 05:01:46 +01:00
MemoryContext child;
2000-08-22 06:00:10 +02:00
AssertArg(MemoryContextIsValid(context));
for (child = context->firstchild; child != NULL; child = child->nextchild)
MemoryContextReset(child);
}
/*
* MemoryContextDelete
* Delete a context and its descendants, and release all space
* allocated therein.
*
* The type-specific delete routine removes all subsidiary storage
* for the context, but we have to delete the context node itself,
2001-03-22 05:01:46 +01:00
* as well as recurse to get the children. We must also delink the
* node from its parent, if it has one.
*/
void
MemoryContextDelete(MemoryContext context)
{
2000-08-22 06:00:10 +02:00
AssertArg(MemoryContextIsValid(context));
/* We had better not be deleting TopMemoryContext ... */
Assert(context != TopMemoryContext);
/* And not CurrentMemoryContext, either */
Assert(context != CurrentMemoryContext);
MemoryContextDeleteChildren(context);
2001-03-22 05:01:46 +01:00
/*
2005-10-15 04:49:52 +02:00
* We delink the context from its parent before deleting it, so that if
* there's an error we won't have deleted/busted contexts still attached
* to the context tree. Better a leak than a crash.
*/
if (context->parent)
{
2001-03-22 05:01:46 +01:00
MemoryContext parent = context->parent;
if (context == parent->firstchild)
parent->firstchild = context->nextchild;
else
{
2001-03-22 05:01:46 +01:00
MemoryContext child;
for (child = parent->firstchild; child; child = child->nextchild)
{
if (context == child->nextchild)
{
child->nextchild = context->nextchild;
break;
}
}
}
}
(*context->methods->delete) (context);
pfree(context);
}
/*
* MemoryContextDeleteChildren
* Delete all the descendants of the named context and release all
* space allocated therein. The named context itself is not touched.
*/
void
MemoryContextDeleteChildren(MemoryContext context)
{
2000-08-22 06:00:10 +02:00
AssertArg(MemoryContextIsValid(context));
2001-03-22 05:01:46 +01:00
/*
2005-10-15 04:49:52 +02:00
* MemoryContextDelete will delink the child from me, so just iterate as
* long as there is a child.
*/
while (context->firstchild != NULL)
MemoryContextDelete(context->firstchild);
}
/*
* MemoryContextResetAndDeleteChildren
* Release all space allocated within a context and delete all
* its descendants.
*
* This is a common combination case where we want to preserve the
* specific context but get rid of absolutely everything under it.
*/
void
MemoryContextResetAndDeleteChildren(MemoryContext context)
{
2000-08-22 06:00:10 +02:00
AssertArg(MemoryContextIsValid(context));
MemoryContextDeleteChildren(context);
(*context->methods->reset) (context);
}
/*
* GetMemoryChunkSpace
* Given a currently-allocated chunk, determine the total space
* it occupies (including all memory-allocation overhead).
*
* This is useful for measuring the total space occupied by a set of
* allocated chunks.
*/
Size
GetMemoryChunkSpace(void *pointer)
{
StandardChunkHeader *header;
/*
* 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.
*/
header = (StandardChunkHeader *)
((char *) pointer - STANDARDCHUNKHEADERSIZE);
AssertArg(MemoryContextIsValid(header->context));
return (*header->context->methods->get_chunk_space) (header->context,
pointer);
}
/*
* GetMemoryChunkContext
* Given a currently-allocated chunk, determine the context
* it belongs to.
*/
MemoryContext
GetMemoryChunkContext(void *pointer)
{
StandardChunkHeader *header;
/*
* 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.
*/
header = (StandardChunkHeader *)
((char *) pointer - STANDARDCHUNKHEADERSIZE);
AssertArg(MemoryContextIsValid(header->context));
return header->context;
}
/*
* MemoryContextIsEmpty
* Is a memory context empty of any allocated space?
*/
bool
MemoryContextIsEmpty(MemoryContext context)
{
AssertArg(MemoryContextIsValid(context));
/*
* For now, we consider a memory context nonempty if it has any children;
* perhaps this should be changed later.
*/
if (context->firstchild != NULL)
return false;
/* Otherwise use the type-specific inquiry */
return (*context->methods->is_empty) (context);
}
/*
* MemoryContextStats
* Print statistics about the named context and all its descendants.
*
* This is just a debugging utility, so it's not fancy. The statistics
* are merely sent to stderr.
*/
void
MemoryContextStats(MemoryContext context)
{
2001-03-22 05:01:46 +01:00
MemoryContext child;
2000-08-22 06:00:10 +02:00
AssertArg(MemoryContextIsValid(context));
(*context->methods->stats) (context);
for (child = context->firstchild; child != NULL; child = child->nextchild)
MemoryContextStats(child);
}
Here is the patch with memory leak checker. This checker allow detect in-chunk leaks, overwrite-next-chunk leaks and overwrite block-freeptr leaks. A in-chunk leak --- if something overwrite space after wanted (via palloc() size, but it is still inside chunk. For example x = palloc(12); /* create 16b chunk */ memset(x, '#', 13); this leak is in the current source total invisible, because chunk is 16b and leak is in the "align space". For this feature I add data_size to StandardChunk, and all memory which go from AllocSetAlloc() is marked as 0x7F. The MemoryContextCheck() is compiled '#ifdef USE_ASSERT_CHECKING'. I add this checking to 'tcop/postgres.c' and is active after each backend query, but it is probably not sufficient, because some MemoryContext exist only during memory processing --- will good if someone who known where it is needful (Tom:-) add it for others contexts; A problem in the current source is that we have still some malloc() allocation that is not needful and this allocation is total invisible for all context routines. For example Dllist in backend (pretty dirty it is in catcache where values in Dllist are palloc-ed, but list is malloc-ed). --- and BTW. this Dllist design stand in the way for query cache :-) Tom, if you agree I start replace some mallocs. BTW. --- Tom, have you idea for across transaction presistent allocation for SQL functions? (like regex - now it is via malloc) I almost forget. I add one if() to AllocSetAlloc(), for 'size' that are greater than ALLOC_BIGCHUNK_LIMIT is not needful check AllocSetFreeIndex(), because 'fidx' is always 'ALLOCSET_NUM_FREELISTS - 1'. It a little brisk up allocation for very large chunks. Right? Karel
2000-07-11 16:30:37 +02:00
/*
* MemoryContextCheck
* Check all chunks in the named context.
*
2001-03-22 05:01:46 +01:00
* This is just a debugging utility, so it's not fancy.
Here is the patch with memory leak checker. This checker allow detect in-chunk leaks, overwrite-next-chunk leaks and overwrite block-freeptr leaks. A in-chunk leak --- if something overwrite space after wanted (via palloc() size, but it is still inside chunk. For example x = palloc(12); /* create 16b chunk */ memset(x, '#', 13); this leak is in the current source total invisible, because chunk is 16b and leak is in the "align space". For this feature I add data_size to StandardChunk, and all memory which go from AllocSetAlloc() is marked as 0x7F. The MemoryContextCheck() is compiled '#ifdef USE_ASSERT_CHECKING'. I add this checking to 'tcop/postgres.c' and is active after each backend query, but it is probably not sufficient, because some MemoryContext exist only during memory processing --- will good if someone who known where it is needful (Tom:-) add it for others contexts; A problem in the current source is that we have still some malloc() allocation that is not needful and this allocation is total invisible for all context routines. For example Dllist in backend (pretty dirty it is in catcache where values in Dllist are palloc-ed, but list is malloc-ed). --- and BTW. this Dllist design stand in the way for query cache :-) Tom, if you agree I start replace some mallocs. BTW. --- Tom, have you idea for across transaction presistent allocation for SQL functions? (like regex - now it is via malloc) I almost forget. I add one if() to AllocSetAlloc(), for 'size' that are greater than ALLOC_BIGCHUNK_LIMIT is not needful check AllocSetFreeIndex(), because 'fidx' is always 'ALLOCSET_NUM_FREELISTS - 1'. It a little brisk up allocation for very large chunks. Right? Karel
2000-07-11 16:30:37 +02:00
*/
#ifdef MEMORY_CONTEXT_CHECKING
void
MemoryContextCheck(MemoryContext context)
{
2001-03-22 05:01:46 +01:00
MemoryContext child;
Here is the patch with memory leak checker. This checker allow detect in-chunk leaks, overwrite-next-chunk leaks and overwrite block-freeptr leaks. A in-chunk leak --- if something overwrite space after wanted (via palloc() size, but it is still inside chunk. For example x = palloc(12); /* create 16b chunk */ memset(x, '#', 13); this leak is in the current source total invisible, because chunk is 16b and leak is in the "align space". For this feature I add data_size to StandardChunk, and all memory which go from AllocSetAlloc() is marked as 0x7F. The MemoryContextCheck() is compiled '#ifdef USE_ASSERT_CHECKING'. I add this checking to 'tcop/postgres.c' and is active after each backend query, but it is probably not sufficient, because some MemoryContext exist only during memory processing --- will good if someone who known where it is needful (Tom:-) add it for others contexts; A problem in the current source is that we have still some malloc() allocation that is not needful and this allocation is total invisible for all context routines. For example Dllist in backend (pretty dirty it is in catcache where values in Dllist are palloc-ed, but list is malloc-ed). --- and BTW. this Dllist design stand in the way for query cache :-) Tom, if you agree I start replace some mallocs. BTW. --- Tom, have you idea for across transaction presistent allocation for SQL functions? (like regex - now it is via malloc) I almost forget. I add one if() to AllocSetAlloc(), for 'size' that are greater than ALLOC_BIGCHUNK_LIMIT is not needful check AllocSetFreeIndex(), because 'fidx' is always 'ALLOCSET_NUM_FREELISTS - 1'. It a little brisk up allocation for very large chunks. Right? Karel
2000-07-11 16:30:37 +02:00
2000-08-22 06:00:10 +02:00
AssertArg(MemoryContextIsValid(context));
Here is the patch with memory leak checker. This checker allow detect in-chunk leaks, overwrite-next-chunk leaks and overwrite block-freeptr leaks. A in-chunk leak --- if something overwrite space after wanted (via palloc() size, but it is still inside chunk. For example x = palloc(12); /* create 16b chunk */ memset(x, '#', 13); this leak is in the current source total invisible, because chunk is 16b and leak is in the "align space". For this feature I add data_size to StandardChunk, and all memory which go from AllocSetAlloc() is marked as 0x7F. The MemoryContextCheck() is compiled '#ifdef USE_ASSERT_CHECKING'. I add this checking to 'tcop/postgres.c' and is active after each backend query, but it is probably not sufficient, because some MemoryContext exist only during memory processing --- will good if someone who known where it is needful (Tom:-) add it for others contexts; A problem in the current source is that we have still some malloc() allocation that is not needful and this allocation is total invisible for all context routines. For example Dllist in backend (pretty dirty it is in catcache where values in Dllist are palloc-ed, but list is malloc-ed). --- and BTW. this Dllist design stand in the way for query cache :-) Tom, if you agree I start replace some mallocs. BTW. --- Tom, have you idea for across transaction presistent allocation for SQL functions? (like regex - now it is via malloc) I almost forget. I add one if() to AllocSetAlloc(), for 'size' that are greater than ALLOC_BIGCHUNK_LIMIT is not needful check AllocSetFreeIndex(), because 'fidx' is always 'ALLOCSET_NUM_FREELISTS - 1'. It a little brisk up allocation for very large chunks. Right? Karel
2000-07-11 16:30:37 +02:00
(*context->methods->check) (context);
for (child = context->firstchild; child != NULL; child = child->nextchild)
MemoryContextCheck(child);
}
#endif
/*
* MemoryContextContains
* Detect whether an allocated chunk of memory belongs to a given
* context or not.
*
* Caution: this test is reliable as long as 'pointer' does point to
* a chunk of memory allocated from *some* context. If 'pointer' points
* at memory obtained in some other way, there is a small chance of a
* false-positive result, since the bits right before it might look like
* a valid chunk header by chance.
*/
bool
MemoryContextContains(MemoryContext context, void *pointer)
{
2001-03-22 05:01:46 +01:00
StandardChunkHeader *header;
/*
* Try to detect bogus pointers handed to us, poorly though we can.
2001-03-22 05:01:46 +01:00
* Presumably, a pointer that isn't MAXALIGNED isn't pointing at an
* allocated chunk.
*/
if (pointer == NULL || pointer != (void *) MAXALIGN(pointer))
return false;
2001-03-22 05:01:46 +01:00
/*
* OK, it's probably safe to look at the chunk header.
*/
header = (StandardChunkHeader *)
((char *) pointer - STANDARDCHUNKHEADERSIZE);
2001-03-22 05:01:46 +01:00
/*
2005-10-15 04:49:52 +02:00
* 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;
}
/*--------------------
* MemoryContextCreate
* Context-type-independent part of context creation.
*
* This is only intended to be called by context-type-specific
* context creation routines, not by the unwashed masses.
*
* The context creation procedure is a little bit tricky because
* we want to be sure that we don't leave the context tree invalid
* in case of failure (such as insufficient memory to allocate the
* context node itself). The procedure goes like this:
* 1. Context-type-specific routine first calls MemoryContextCreate(),
* passing the appropriate tag/size/methods values (the methods
* pointer will ordinarily point to statically allocated data).
* The parent and name parameters usually come from the caller.
* 2. MemoryContextCreate() attempts to allocate the context node,
* plus space for the name. If this fails we can ereport() with no
* damage done.
* 3. We fill in all of the type-independent MemoryContext fields.
* 4. We call the type-specific init routine (using the methods pointer).
* The init routine is required to make the node minimally valid
* with zero chance of failure --- it can't allocate more memory,
* for example.
* 5. Now we have a minimally valid node that can behave correctly
* when told to reset or delete itself. We link the node to its
* parent (if any), making the node part of the context tree.
* 6. We return to the context-type-specific routine, which finishes
* up type-specific initialization. This routine can now do things
* that might fail (like allocate more memory), so long as it's
* sure the node is left in a state that delete will handle.
*
* This protocol doesn't prevent us from leaking memory if step 6 fails
* during creation of a top-level context, since there's no parent link
* in that case. However, if you run out of memory while you're building
* a top-level context, you might as well go home anyway...
*
* Normally, the context node and the name are allocated from
* TopMemoryContext (NOT from the parent context, since the node must
2001-03-22 05:01:46 +01:00
* survive resets of its parent context!). However, this routine is itself
* used to create TopMemoryContext! If we see that TopMemoryContext is NULL,
* we assume we are creating TopMemoryContext and use malloc() to allocate
* the node.
*
* Note that the name field of a MemoryContext does not point to
* separately-allocated storage, so it should not be freed at context
* deletion.
*--------------------
*/
MemoryContext
MemoryContextCreate(NodeTag tag, Size size,
MemoryContextMethods *methods,
MemoryContext parent,
const char *name)
{
2001-03-22 05:01:46 +01:00
MemoryContext node;
Size needed = size + strlen(name) + 1;
/* Get space for node and name */
if (TopMemoryContext != NULL)
{
/* Normal case: allocate the node in TopMemoryContext */
node = (MemoryContext) MemoryContextAlloc(TopMemoryContext,
needed);
}
else
{
/* Special case for startup: use good ol' malloc */
node = (MemoryContext) malloc(needed);
Assert(node != NULL);
}
/* Initialize the node as best we can */
MemSet(node, 0, size);
node->type = tag;
node->methods = methods;
node->parent = NULL; /* for the moment */
node->firstchild = NULL;
node->nextchild = NULL;
node->name = ((char *) node) + size;
strcpy(node->name, name);
/* Type-specific routine finishes any other essential initialization */
(*node->methods->init) (node);
/* OK to link node to parent (if any) */
if (parent)
{
node->parent = parent;
node->nextchild = parent->firstchild;
parent->firstchild = node;
}
/* Return to type-specific creation routine to finish up */
return node;
}
/*
* 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.
*/
void *
MemoryContextAlloc(MemoryContext context, Size size)
{
AssertArg(MemoryContextIsValid(context));
if (!AllocSizeIsValid(size))
elog(ERROR, "invalid memory alloc request size %lu",
(unsigned long) size);
return (*context->methods->alloc) (context, size);
}
/*
* 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)
{
2003-08-04 02:43:34 +02:00
void *ret;
AssertArg(MemoryContextIsValid(context));
if (!AllocSizeIsValid(size))
elog(ERROR, "invalid memory alloc request size %lu",
(unsigned long) size);
ret = (*context->methods->alloc) (context, size);
MemSetAligned(ret, 0, size);
return ret;
}
/*
* 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)
{
2003-08-04 02:43:34 +02:00
void *ret;
AssertArg(MemoryContextIsValid(context));
if (!AllocSizeIsValid(size))
elog(ERROR, "invalid memory alloc request size %lu",
(unsigned long) size);
ret = (*context->methods->alloc) (context, size);
MemSetLoop(ret, 0, size);
return ret;
}
/*
* pfree
* Release an allocated chunk.
*/
void
pfree(void *pointer)
{
2001-03-22 05:01:46 +01:00
StandardChunkHeader *header;
/*
* Try to detect bogus pointers handed to us, poorly though we can.
2001-03-22 05:01:46 +01:00
* Presumably, a pointer that isn't MAXALIGNED isn't pointing at an
* allocated chunk.
*/
Assert(pointer != NULL);
Assert(pointer == (void *) MAXALIGN(pointer));
2001-03-22 05:01:46 +01:00
/*
* OK, it's probably safe to look at the chunk header.
*/
header = (StandardChunkHeader *)
((char *) pointer - STANDARDCHUNKHEADERSIZE);
AssertArg(MemoryContextIsValid(header->context));
2001-03-22 05:01:46 +01:00
(*header->context->methods->free_p) (header->context, pointer);
}
/*
* repalloc
* Adjust the size of a previously allocated chunk.
*/
void *
repalloc(void *pointer, Size size)
{
2001-03-22 05:01:46 +01:00
StandardChunkHeader *header;
/*
* Try to detect bogus pointers handed to us, poorly though we can.
2001-03-22 05:01:46 +01:00
* Presumably, a pointer that isn't MAXALIGNED isn't pointing at an
* allocated chunk.
*/
Assert(pointer != NULL);
Assert(pointer == (void *) MAXALIGN(pointer));
2001-03-22 05:01:46 +01:00
/*
* OK, it's probably safe to look at the chunk header.
*/
header = (StandardChunkHeader *)
((char *) pointer - STANDARDCHUNKHEADERSIZE);
AssertArg(MemoryContextIsValid(header->context));
if (!AllocSizeIsValid(size))
elog(ERROR, "invalid memory alloc request size %lu",
(unsigned long) size);
2001-03-22 05:01:46 +01:00
return (*header->context->methods->realloc) (header->context,
pointer, size);
}
/*
* MemoryContextSwitchTo
* Returns the current context; installs the given context.
*
* This is inlined when using GCC.
*
* TODO: investigate supporting inlining for some non-GCC compilers.
*/
#ifndef __GNUC__
MemoryContext
MemoryContextSwitchTo(MemoryContext context)
{
MemoryContext old;
AssertArg(MemoryContextIsValid(context));
old = CurrentMemoryContext;
CurrentMemoryContext = context;
return old;
}
#endif /* ! __GNUC__ */
/*
* MemoryContextStrdup
* Like strdup(), but allocate from the specified context
*/
char *
MemoryContextStrdup(MemoryContext context, const char *string)
{
char *nstr;
Size len = strlen(string) + 1;
nstr = (char *) MemoryContextAlloc(context, len);
memcpy(nstr, string, len);
return nstr;
}
#if defined(WIN32) || defined(__CYGWIN__)
/*
* Memory support routines for libpgport on Win32
*
* Win32 can't load a library that DLLIMPORTs a variable
* if the link object files also DLLIMPORT the same variable.
* For this reason, libpgport can't reference CurrentMemoryContext
* in the palloc macro calls.
*
* To fix this, we create several functions here that allow us to
* manage memory without doing the inline in libpgport.
*/
void *
pgport_palloc(Size sz)
{
return palloc(sz);
}
char *
pgport_pstrdup(const char *str)
{
return pstrdup(str);
}
/* Doesn't reference a DLLIMPORT variable, but here for completeness. */
void
pgport_pfree(void *pointer)
{
pfree(pointer);
}
2004-08-29 07:07:03 +02:00
2004-10-18 01:39:22 +02:00
#endif