mirror of
https://github.com/postgres/postgres.git
synced 2025-05-01 01:04:50 +03:00
Invent a new memory context primitive, MemoryContextSetParent.
This function will be useful for altering the lifespan of a context after creation (for example, by creating it under a transient context and later reparenting it to belong to a long-lived context). It costs almost no new code, since we can refactor what was there. Per my proposal of yesterday.
This commit is contained in:
parent
5f42e5945b
commit
b0025bd957
@ -178,26 +178,8 @@ MemoryContextDelete(MemoryContext context)
|
|||||||
* there's an error we won't have deleted/busted contexts still attached
|
* there's an error we won't have deleted/busted contexts still attached
|
||||||
* to the context tree. Better a leak than a crash.
|
* to the context tree. Better a leak than a crash.
|
||||||
*/
|
*/
|
||||||
if (context->parent)
|
MemoryContextSetParent(context, NULL);
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(*context->methods->delete_context) (context);
|
(*context->methods->delete_context) (context);
|
||||||
pfree(context);
|
pfree(context);
|
||||||
}
|
}
|
||||||
@ -237,6 +219,67 @@ MemoryContextResetAndDeleteChildren(MemoryContext context)
|
|||||||
MemoryContextReset(context);
|
MemoryContextReset(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);
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GetMemoryChunkSpace
|
* GetMemoryChunkSpace
|
||||||
* Given a currently-allocated chunk, determine the total space
|
* Given a currently-allocated chunk, determine the total space
|
||||||
@ -489,6 +532,7 @@ MemoryContextCreate(NodeTag tag, Size size,
|
|||||||
(*node->methods->init) (node);
|
(*node->methods->init) (node);
|
||||||
|
|
||||||
/* OK to link node to parent (if any) */
|
/* OK to link node to parent (if any) */
|
||||||
|
/* Could use MemoryContextSetParent here, but doesn't seem worthwhile */
|
||||||
if (parent)
|
if (parent)
|
||||||
{
|
{
|
||||||
node->parent = parent;
|
node->parent = parent;
|
||||||
|
@ -90,6 +90,8 @@ extern void MemoryContextDelete(MemoryContext context);
|
|||||||
extern void MemoryContextResetChildren(MemoryContext context);
|
extern void MemoryContextResetChildren(MemoryContext context);
|
||||||
extern void MemoryContextDeleteChildren(MemoryContext context);
|
extern void MemoryContextDeleteChildren(MemoryContext context);
|
||||||
extern void MemoryContextResetAndDeleteChildren(MemoryContext context);
|
extern void MemoryContextResetAndDeleteChildren(MemoryContext context);
|
||||||
|
extern void MemoryContextSetParent(MemoryContext context,
|
||||||
|
MemoryContext new_parent);
|
||||||
extern Size GetMemoryChunkSpace(void *pointer);
|
extern Size GetMemoryChunkSpace(void *pointer);
|
||||||
extern MemoryContext GetMemoryChunkContext(void *pointer);
|
extern MemoryContext GetMemoryChunkContext(void *pointer);
|
||||||
extern bool MemoryContextIsEmpty(MemoryContext context);
|
extern bool MemoryContextIsEmpty(MemoryContext context);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user