Improve performance in freeing memory contexts
authorKevin Grittner <[email protected]>
Tue, 8 Dec 2015 23:32:49 +0000 (17:32 -0600)
committerKevin Grittner <[email protected]>
Tue, 8 Dec 2015 23:32:49 +0000 (17:32 -0600)
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

src/backend/utils/mmgr/mcxt.c
src/include/nodes/memnodes.h

index 705f3ef279130cc49ef0ccd152a6ddd3cd9ad4a9..82cd71df6a8ae3546e039395b74c2dbc21e09924 100644 (file)
@@ -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;
index 577ab9cb1f9560ebc0364d7f390a52588fa16fea..bbb58bd15eb7dd6bb148f52d7d9fc14d64f6de7c 100644 (file)
@@ -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 */