Пример #1
0
/*
 * 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 %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);
	VALGRIND_MEMPOOL_CHANGE(context, pointer, ret, size);

	return ret;
}
Пример #2
0
/*
 * 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,
 * 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)
{
	AssertArg(MemoryContextIsValid(context));
	/* We had better not be deleting TopMemoryContext ... */
	Assert(context != TopMemoryContext);
	/* And not CurrentMemoryContext, either */
	Assert(context != CurrentMemoryContext);

	MemoryContextDeleteChildren(context);

	/*
	 * It's not entirely clear whether 'tis better to do this before or after
	 * delinking the context; but an error in a callback will likely result in
	 * leaking the whole context (if it's not a root context) if we do it
	 * after, so let's do it before.
	 */
	MemoryContextCallResetCallbacks(context);

	/*
	 * 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.
	 */
	MemoryContextSetParent(context, NULL);

	(*context->methods->delete_context) (context);
	VALGRIND_DESTROY_MEMPOOL(context);
	pfree(context);
}
Пример #3
0
/*
 * MemoryContextAllowInCriticalSection
 *		Allow/disallow allocations in this memory context within a critical
 *		section.
 *
 * Normally, memory allocations are not allowed within a critical section,
 * because a failure would lead to PANIC.  There are a few exceptions to
 * that, like allocations related to debugging code that is not supposed to
 * be enabled in production.  This function can be used to exempt specific
 * memory contexts from the assertion in palloc().
 */
void
MemoryContextAllowInCriticalSection(MemoryContext context, bool allow)
{
	AssertArg(MemoryContextIsValid(context));

	context->allowInCritSection = allow;
}
Пример #4
0
/*
 * MemoryContextGetParent
 *		Get the parent context (if any) of the specified context
 */
MemoryContext
MemoryContextGetParent(MemoryContext context)
{
	AssertArg(MemoryContextIsValid(context));

	return context->parent;
}
Пример #5
0
/*
 * MemoryContextStats
 *		Prints the usage details of a context.
 *
 * Parameters:
 * 		context: the context of interest.
 */
void
MemoryContextStats(MemoryContext context)
{
    char*     name;
    char      namebuf[MAX_CONTEXT_NAME_SIZE];

	AssertArg(MemoryContextIsValid(context));

    name = MemoryContextName(context, NULL, namebuf, sizeof(namebuf));
    write_stderr("pid %d: Memory statistics for %s/\n", MyProcPid, name);
    write_stderr("context: occurrences_count, currently_allocated, currently_available, total_allocated, total_freed, name\n");

	uint64 nBlocks = 0;
	uint64 nChunks = 0;
	uint64 currentAvailable = 0;
	uint64 allAllocated = 0;
	uint64 allFreed = 0;
	uint64 maxHeld = 0;
	int namebufsize = sizeof(namebuf);

	/* Get the root context's stat and pass it to the MemoryContextStats_recur for printing */
	(*context->methods.stats)(context, &nBlocks, &nChunks, &currentAvailable, &allAllocated, &allFreed, &maxHeld);
	name = MemoryContextName(context, context, namebuf, namebufsize);

    MemoryContextStats_recur(context, context, name, namebuf, namebufsize, nBlocks, nChunks,
    		currentAvailable, allAllocated, allFreed, maxHeld);
}
Пример #6
0
/*
 * 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 *
MemoryContextAllocZeroAlignedImpl(MemoryContext context, Size size, const char* sfile, const char *sfunc, int sline)
{
	void	   *ret;

#ifdef PGTRACE_ENABLED
	StandardChunkHeader *header;
#endif

	AssertArg(MemoryContextIsValid(context));

#ifdef CDB_PALLOC_CALLER_ID
	context->callerFile = sfile;
	context->callerLine = sline;
#endif

	if (!AllocSizeIsValid(size))
		MemoryContextError(ERRCODE_INTERNAL_ERROR,
				context, CDB_MCXT_WHERE(context),
				"invalid memory alloc request size %lu",
				(unsigned long)size);

	ret = (*context->methods.alloc) (context, size);

	MemSetLoop(ret, 0, size);

#ifdef PGTRACE_ENABLED
	header = (StandardChunkHeader *)
		((char *) ret - STANDARDCHUNKHEADERSIZE);
	PG_TRACE5(memctxt__alloc, size, header->size, 0, 0, (long) context->name);
#endif

	return ret;
}
Пример #7
0
/*
 * 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)
	{
		MemoryContextStats(TopMemoryContext);
		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;
}
Пример #8
0
/*
 * MemoryContextAllocExtended
 *		Allocate space within the specified context using the given flags.
 */
void *
MemoryContextAllocExtended(MemoryContext context, Size size, int flags)
{
	void	   *ret;

	AssertArg(MemoryContextIsValid(context));
	AssertNotInCriticalSection(context);

	if (((flags & MCXT_ALLOC_HUGE) != 0 && !AllocHugeSizeIsValid(size)) ||
		((flags & MCXT_ALLOC_HUGE) == 0 && !AllocSizeIsValid(size)))
		elog(ERROR, "invalid memory alloc request size %zu", size);

	context->isReset = false;

	ret = (*context->methods->alloc) (context, size);
	if (ret == NULL)
	{
		if ((flags & MCXT_ALLOC_NO_OOM) == 0)
		{
			MemoryContextStats(TopMemoryContext);
			ereport(ERROR,
					(errcode(ERRCODE_OUT_OF_MEMORY),
					 errmsg("out of memory"),
					 errdetail("Failed on request of size %zu.", size)));
		}
		return NULL;
	}

	VALGRIND_MEMPOOL_ALLOC(context, ret, size);

	if ((flags & MCXT_ALLOC_ZERO) != 0)
		MemSetAligned(ret, 0, size);

	return ret;
}
Пример #9
0
/*
 * repalloc
 *		Adjust the size of a previously allocated chunk.
 */
void *
repalloc(void *pointer, Size size)
{
	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));

	if (!AllocSizeIsValid(size))
		elog(ERROR, "invalid memory alloc request size %lu",
			 (unsigned long) size);

	/* isReset must be false already */
	Assert(!header->context->isReset);

	return (*header->context->methods->realloc) (header->context,
												 pointer, size);
}
Пример #10
0
void *
palloc0(Size size)
{
	/* duplicates MemoryContextAllocZero to avoid increased overhead */
	void	   *ret;

	AssertArg(MemoryContextIsValid(CurrentMemoryContext));
	AssertNotInCriticalSection(CurrentMemoryContext);

	if (!AllocSizeIsValid(size))
		elog(ERROR, "invalid memory alloc request size %zu", size);

	CurrentMemoryContext->isReset = false;

	ret = (*CurrentMemoryContext->methods->alloc) (CurrentMemoryContext, size);
	if (ret == NULL)
	{
		MemoryContextStats(TopMemoryContext);
		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);

	return ret;
}
Пример #11
0
/*
 * 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)
{
	AssertArg(MemoryContextIsValid(context));

	MemoryContextDeleteChildren(context);
	MemoryContextReset(context);
}
Пример #12
0
/*
 * 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)
{
	AssertArg(MemoryContextIsValid(context));

	MemoryContextDeleteChildren(context);
	(*context->methods.reset) (context);
}
/*
 * MemoryContextSetParent
 *		Change a context to belong to a new parent (or no parent).
 *
 * We provide this as an API function because it is sometimes useful to
 * change a context's lifespan after creation.  For example, a context
 * might be created underneath a transient context, filled with data,
 * and then reparented underneath CacheMemoryContext to make it long-lived.
 * In this way no special effort is needed to get rid of the context in case
 * a failure occurs before its contents are completely set up.
 *
 * Callers often assume that this function cannot fail, so don't put any
 * elog(ERROR) calls in it.
 *
 * A possible caller error is to reparent a context under itself, creating
 * a loop in the context graph.  We assert here that context != new_parent,
 * but checking for multi-level loops seems more trouble than it's worth.
 */
void
MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
{
	AssertArg(MemoryContextIsValid(context));
	AssertArg(context != new_parent);

	/* Fast path if it's got correct parent already */
	if (new_parent == context->parent)
		return;

	/* Delink from existing parent, if any */
	if (context->parent)
	{
		MemoryContext parent = context->parent;

		if (context == parent->firstchild)
			parent->firstchild = context->nextchild;
		else
		{
			MemoryContext child;

			for (child = parent->firstchild; child; child = child->nextchild)
			{
				if (context == child->nextchild)
				{
					child->nextchild = context->nextchild;
					break;
				}
			}
		}
	}

	/* And relink */
	if (new_parent)
	{
		AssertArg(MemoryContextIsValid(new_parent));
		context->parent = new_parent;
		context->nextchild = new_parent->firstchild;
		new_parent->firstchild = context;
	}
	else
	{
		context->parent = NULL;
		context->nextchild = NULL;
	}
}
Пример #14
0
/*
 * MemoryContextSetParent
 *		Change a context to belong to a new parent (or no parent).
 *
 * We provide this as an API function because it is sometimes useful to
 * change a context's lifespan after creation.  For example, a context
 * might be created underneath a transient context, filled with data,
 * and then reparented underneath CacheMemoryContext to make it long-lived.
 * In this way no special effort is needed to get rid of the context in case
 * a failure occurs before its contents are completely set up.
 *
 * Callers often assume that this function cannot fail, so don't put any
 * elog(ERROR) calls in it.
 *
 * A possible caller error is to reparent a context under itself, creating
 * a loop in the context graph.  We assert here that context != new_parent,
 * but checking for multi-level loops seems more trouble than it's worth.
 */
void
MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
{
	AssertArg(MemoryContextIsValid(context));
	AssertArg(context != new_parent);

	/* Fast path if it's got correct parent already */
	if (new_parent == context->parent)
		return;

	/* Delink from existing parent, if any */
	if (context->parent)
	{
		MemoryContext parent = context->parent;

		if (context->prevchild != NULL)
			context->prevchild->nextchild = context->nextchild;
		else
		{
			Assert(parent->firstchild == context);
			parent->firstchild = context->nextchild;
		}

		if (context->nextchild != NULL)
			context->nextchild->prevchild = context->prevchild;
	}

	/* And relink */
	if (new_parent)
	{
		AssertArg(MemoryContextIsValid(new_parent));
		context->parent = new_parent;
		context->prevchild = NULL;
		context->nextchild = new_parent->firstchild;
		if (new_parent->firstchild != NULL)
			new_parent->firstchild->prevchild = context;
		new_parent->firstchild = context;
	}
	else
	{
		context->parent = NULL;
		context->prevchild = NULL;
		context->nextchild = NULL;
	}
}
Пример #15
0
/*
 * MemoryContextGetCurrentSpace
 *		Return the number of bytes currently occupied by the memory context.
 *
 * This is the amount of space obtained from the lower-level source of the
 * memory (e.g. malloc) and not yet released back to that source.  Includes
 * overhead and free space held and managed within this context by the
 * context-type-specific memory manager.
 */
Size
MemoryContextGetCurrentSpace(MemoryContext context)
{
	AssertArg(MemoryContextIsValid(context));
    Assert(context->allBytesAlloc >= context->allBytesFreed);
    Assert(context->allBytesAlloc - context->allBytesFreed < SIZE_MAX);

    return (Size)(context->allBytesAlloc - context->allBytesFreed);
}                               /* MemoryContextGetCurrentSpace */
Пример #16
0
/*
 * repalloc
 *		Adjust the size of a previously allocated chunk.
 */
void *
MemoryContextReallocImpl(void *pointer, Size size, const char *sfile, const char *sfunc, int sline)
{
	StandardChunkHeader *header;
	void *ret;

#ifdef PGTRACE_ENABLED 
	long old_reqsize;
	long old_size;
#endif

	/*
	 * 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->sharedHeader->context));

#ifdef PGTRACE_ENABLED
#ifdef MEMORY_CONTEXT_CHECKING
	old_reqsize = header->requested_size;
#else
	old_reqsize = 0;
#endif
	old_size = header->size;
#endif

#ifdef CDB_PALLOC_CALLER_ID
	header->sharedHeader->context->callerFile = sfile;
	header->sharedHeader->context->callerLine = sline;
#endif

	if (!AllocSizeIsValid(size))
		MemoryContextError(ERRCODE_INTERNAL_ERROR,
				header->sharedHeader->context, CDB_MCXT_WHERE(header->sharedHeader->context),
				"invalid memory alloc request size %lu",
				(unsigned long)size);

	ret = (*header->sharedHeader->context->methods.realloc) (header->sharedHeader->context, pointer, size);

#ifdef PGTRACE_ENABLED
	header = (StandardChunkHeader *)
		((char *) ret - STANDARDCHUNKHEADERSIZE);
	PG_TRACE5(memctxt__realloc, size, header->size, old_reqsize, old_size, (long) header->sharedHeader->context->name);
#endif

	return ret;
}
Пример #17
0
static void
getMemoryContextStat(MemoryContext context, MemoryContextCounters *stat)
{
	AssertArg(MemoryContextIsValid(context));

	/* Examine the context itself */
	memset(stat, 0, sizeof(*stat));
	(*context->methods->stats) (context, 0, false, stat);
}
Пример #18
0
/*
 * Delete the MPool object and its related space.
 */
void
mpool_delete(MPool *mpool)
{
    Assert(mpool != NULL && mpool->context != NULL);
    Assert(MemoryContextIsValid(mpool->context));

    mpool_reset(mpool);
    MemoryContextDelete(mpool->context);
    pfree(mpool);
}
Пример #19
0
/*
 * 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)
{
	MemoryContext child;

	AssertArg(MemoryContextIsValid(context));

	for (child = context->firstchild; child != NULL; child = child->nextchild)
		MemoryContextReset(child);
}
Пример #20
0
static void
MemoryContextStatsInternal(MemoryContext context, int level)
{
	MemoryContext child;

	AssertArg(MemoryContextIsValid(context));

	(*context->methods->stats) (context, level);
	for (child = context->firstchild; child != NULL; child = child->nextchild)
		MemoryContextStatsInternal(child, level + 1);
}
Пример #21
0
void
MemoryContextCheck(MemoryContext context)
{
	MemoryContext child;

	AssertArg(MemoryContextIsValid(context));

	(*context->methods->check) (context);
	for (child = context->firstchild; child != NULL; child = child->nextchild)
		MemoryContextCheck(child);
}
Пример #22
0
/*
 * 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)
{
	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);
}
Пример #23
0
/*
 * HandleMemoryAccountingGenerationOverflowChildren
 * 		Companion method for HandleMemoryAccountingGenerationOverflow(). Used for
 * 		walking the memory context tree.
 *
 * Parameters:
 * 		context: The memory context whose children will be descended
 */
static void
HandleMemoryAccountingGenerationOverflowChildren(MemoryContext context)
{
	MemoryContext child;

	AssertArg(MemoryContextIsValid(context));

	for (child = context->firstchild; child != NULL; child = child->nextchild)
	{
		HandleMemoryAccountingGenerationOverflow(child);
	}
}
Пример #24
0
/*
 * MemoryContextRegisterResetCallback
 *		Register a function to be called before next context reset/delete.
 *		Such callbacks will be called in reverse order of registration.
 *
 * The caller is responsible for allocating a MemoryContextCallback struct
 * to hold the info about this callback request, and for filling in the
 * "func" and "arg" fields in the struct to show what function to call with
 * what argument.  Typically the callback struct should be allocated within
 * the specified context, since that means it will automatically be freed
 * when no longer needed.
 *
 * There is no API for deregistering a callback once registered.  If you
 * want it to not do anything anymore, adjust the state pointed to by its
 * "arg" to indicate that.
 */
void
MemoryContextRegisterResetCallback(MemoryContext context,
								   MemoryContextCallback *cb)
{
	AssertArg(MemoryContextIsValid(context));

	/* Push onto head so this will be called before older registrants. */
	cb->next = context->reset_cbs;
	context->reset_cbs = cb;
	/* Mark the context as non-reset (it probably is already). */
	context->isReset = false;
}
Пример #25
0
/*
 * 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)
{
	AssertArg(MemoryContextIsValid(context));

	/*
	 * MemoryContextDelete will delink the child from me, so just iterate as
	 * long as there is a child.
	 */
	while (context->firstchild != NULL)
		MemoryContextDelete(context->firstchild);
}
Пример #26
0
/*
 * HandleMemoryAccountingGenerationOverflow
 * 		Descends the memory context tree rooted at "context" and calls update_generation
 * 		on each context. The update_generation is supposed to look for every active chunks
 * 		and set their ownership to RolloverAccount.The update_generation method will also
 * 		set the generation of every active chunk to MemoryAccountingCurrentGeneration.
 *
 * Parameters:
 * 		context: The memory context whose children will be descended
 */
static void
HandleMemoryAccountingGenerationOverflow(MemoryContext context)
{
	AssertArg(MemoryContextIsValid(context));

	/* save a function call in common case where there are no children */
	if (context->firstchild != NULL)
	{
		HandleMemoryAccountingGenerationOverflowChildren(context);
	}

	(*context->methods.update_generation) (context);
}
Пример #27
0
/*
 * MemoryContextReset
 *		Release all space allocated within a context and delete all its
 *		descendant contexts (but not the named context itself).
 */
void
MemoryContextReset(MemoryContext context)
{
	AssertArg(MemoryContextIsValid(context));

	/* save a function call in common case where there are no children */
	if (context->firstchild != NULL)
		MemoryContextDeleteChildren(context);

	/* save a function call if no pallocs since startup or last reset */
	if (!context->isReset)
		MemoryContextResetOnly(context);
}
Пример #28
0
/*
 * 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);

	context->isReset = false;

	return (*context->methods->alloc) (context, size);
}
Пример #29
0
/*
 * 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);
}
Пример #30
0
/*
 * Release all objects in the pool, and reset the memory context.
 */
void
mpool_reset(MPool *mpool)
{
    Assert(mpool != NULL && mpool->context != NULL);
    Assert(MemoryContextIsValid(mpool->context));

    elog(DEBUG2, "MPool: total_bytes_allocated=" INT64_FORMAT
         ", bytes_used=" INT64_FORMAT ", bytes_wasted=" INT64_FORMAT,
         mpool->total_bytes_allocated, mpool->bytes_used,
         mpool->bytes_wasted);

    MemoryContextReset(mpool->context);
    mpool_init(mpool);
}