summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Grittner2015-12-08 23:32:49 +0000
committerKevin Grittner2015-12-08 23:32:49 +0000
commit25c539233044c235e97fd7c9dc600fb5f08fe065 (patch)
tree0410cf09723344b326ddd992475273253cec9415
parent521f0458dcd7bb28636250cdfce9b1a3020cff4c (diff)
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
-rw-r--r--src/backend/utils/mmgr/mcxt.c26
-rw-r--r--src/include/nodes/memnodes.h1
2 files changed, 15 insertions, 12 deletions
diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c
index 705f3ef279..82cd71df6a 100644
--- a/src/backend/utils/mmgr/mcxt.c
+++ b/src/backend/utils/mmgr/mcxt.c
@@ -331,21 +331,16 @@ MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
{
MemoryContext parent = context->parent;
- if (context == parent->firstchild)
- parent->firstchild = context->nextchild;
+ if (context->prevchild != NULL)
+ context->prevchild->nextchild = context->nextchild;
else
{
- MemoryContext child;
-
- for (child = parent->firstchild; child; child = child->nextchild)
- {
- if (context == child->nextchild)
- {
- child->nextchild = context->nextchild;
- break;
- }
- }
+ Assert(parent->firstchild == context);
+ parent->firstchild = context->nextchild;
}
+
+ if (context->nextchild != NULL)
+ context->nextchild->prevchild = context->prevchild;
}
/* And relink */
@@ -353,12 +348,16 @@ MemoryContextSetParent(MemoryContext context, MemoryContext 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;
}
}
@@ -714,6 +713,7 @@ MemoryContextCreate(NodeTag tag, Size size,
node->methods = methods;
node->parent = NULL; /* for the moment */
node->firstchild = NULL;
+ node->prevchild = NULL;
node->nextchild = NULL;
node->isReset = true;
node->name = ((char *) node) + size;
@@ -728,6 +728,8 @@ MemoryContextCreate(NodeTag tag, Size size,
{
node->parent = parent;
node->nextchild = parent->firstchild;
+ if (parent->firstchild != NULL)
+ parent->firstchild->prevchild = node;
parent->firstchild = node;
/* inherit allowInCritSection flag from parent */
node->allowInCritSection = parent->allowInCritSection;
diff --git a/src/include/nodes/memnodes.h b/src/include/nodes/memnodes.h
index 577ab9cb1f..bbb58bd15e 100644
--- a/src/include/nodes/memnodes.h
+++ b/src/include/nodes/memnodes.h
@@ -79,6 +79,7 @@ typedef struct MemoryContextData
MemoryContextMethods *methods; /* virtual function table */
MemoryContext parent; /* NULL if no parent (toplevel context) */
MemoryContext firstchild; /* head of linked list of children */
+ MemoryContext prevchild; /* previous child of same parent */
MemoryContext nextchild; /* next child of same parent */
char *name; /* context name (just for debugging) */
MemoryContextCallback *reset_cbs; /* list of reset/delete callbacks */