Commit 25c53923 authored by Kevin Grittner's avatar Kevin Grittner

Improve performance in freeing memory contexts

The single linked list of memory contexts could result in O(N^2)
performance to free a set of contexts if they were not freed in
reverse order of creation.  In many cases the reverse order was
used, but there were some significant exceptions that caused real-
world performance problems.  Rather than requiring all callers to
care about the order in which contexts were freed, and hunting down
and changing all existing cases where the wrong order was used, we
add one pointer per memory context so that the implementation
details are not so visible.

Jan Wieck
parent 521f0458
...@@ -331,21 +331,16 @@ MemoryContextSetParent(MemoryContext context, MemoryContext new_parent) ...@@ -331,21 +331,16 @@ MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
{ {
MemoryContext parent = context->parent; MemoryContext parent = context->parent;
if (context == parent->firstchild) if (context->prevchild != NULL)
parent->firstchild = context->nextchild; context->prevchild->nextchild = context->nextchild;
else else
{ {
MemoryContext child; Assert(parent->firstchild == context);
parent->firstchild = context->nextchild;
for (child = parent->firstchild; child; child = child->nextchild)
{
if (context == child->nextchild)
{
child->nextchild = context->nextchild;
break;
}
}
} }
if (context->nextchild != NULL)
context->nextchild->prevchild = context->prevchild;
} }
/* And relink */ /* And relink */
...@@ -353,12 +348,16 @@ MemoryContextSetParent(MemoryContext context, MemoryContext new_parent) ...@@ -353,12 +348,16 @@ MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
{ {
AssertArg(MemoryContextIsValid(new_parent)); AssertArg(MemoryContextIsValid(new_parent));
context->parent = new_parent; context->parent = new_parent;
context->prevchild = NULL;
context->nextchild = new_parent->firstchild; context->nextchild = new_parent->firstchild;
if (new_parent->firstchild != NULL)
new_parent->firstchild->prevchild = context;
new_parent->firstchild = context; new_parent->firstchild = context;
} }
else else
{ {
context->parent = NULL; context->parent = NULL;
context->prevchild = NULL;
context->nextchild = NULL; context->nextchild = NULL;
} }
} }
...@@ -714,6 +713,7 @@ MemoryContextCreate(NodeTag tag, Size size, ...@@ -714,6 +713,7 @@ MemoryContextCreate(NodeTag tag, Size size,
node->methods = methods; node->methods = methods;
node->parent = NULL; /* for the moment */ node->parent = NULL; /* for the moment */
node->firstchild = NULL; node->firstchild = NULL;
node->prevchild = NULL;
node->nextchild = NULL; node->nextchild = NULL;
node->isReset = true; node->isReset = true;
node->name = ((char *) node) + size; node->name = ((char *) node) + size;
...@@ -728,6 +728,8 @@ MemoryContextCreate(NodeTag tag, Size size, ...@@ -728,6 +728,8 @@ MemoryContextCreate(NodeTag tag, Size size,
{ {
node->parent = parent; node->parent = parent;
node->nextchild = parent->firstchild; node->nextchild = parent->firstchild;
if (parent->firstchild != NULL)
parent->firstchild->prevchild = node;
parent->firstchild = node; parent->firstchild = node;
/* inherit allowInCritSection flag from parent */ /* inherit allowInCritSection flag from parent */
node->allowInCritSection = parent->allowInCritSection; node->allowInCritSection = parent->allowInCritSection;
......
...@@ -79,6 +79,7 @@ typedef struct MemoryContextData ...@@ -79,6 +79,7 @@ typedef struct MemoryContextData
MemoryContextMethods *methods; /* virtual function table */ MemoryContextMethods *methods; /* virtual function table */
MemoryContext parent; /* NULL if no parent (toplevel context) */ MemoryContext parent; /* NULL if no parent (toplevel context) */
MemoryContext firstchild; /* head of linked list of children */ MemoryContext firstchild; /* head of linked list of children */
MemoryContext prevchild; /* previous child of same parent */
MemoryContext nextchild; /* next child of same parent */ MemoryContext nextchild; /* next child of same parent */
char *name; /* context name (just for debugging) */ char *name; /* context name (just for debugging) */
MemoryContextCallback *reset_cbs; /* list of reset/delete callbacks */ MemoryContextCallback *reset_cbs; /* list of reset/delete callbacks */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment