Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 25c5392

Browse files
committed
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
1 parent 521f045 commit 25c5392

File tree

2 files changed

+15
-12
lines changed

2 files changed

+15
-12
lines changed

src/backend/utils/mmgr/mcxt.c

+14-12
Original file line numberDiff line numberDiff line change
@@ -331,34 +331,33 @@ MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
331331
{
332332
MemoryContext parent = context->parent;
333333

334-
if (context == parent->firstchild)
335-
parent->firstchild = context->nextchild;
334+
if (context->prevchild != NULL)
335+
context->prevchild->nextchild = context->nextchild;
336336
else
337337
{
338-
MemoryContext child;
339-
340-
for (child = parent->firstchild; child; child = child->nextchild)
341-
{
342-
if (context == child->nextchild)
343-
{
344-
child->nextchild = context->nextchild;
345-
break;
346-
}
347-
}
338+
Assert(parent->firstchild == context);
339+
parent->firstchild = context->nextchild;
348340
}
341+
342+
if (context->nextchild != NULL)
343+
context->nextchild->prevchild = context->prevchild;
349344
}
350345

351346
/* And relink */
352347
if (new_parent)
353348
{
354349
AssertArg(MemoryContextIsValid(new_parent));
355350
context->parent = new_parent;
351+
context->prevchild = NULL;
356352
context->nextchild = new_parent->firstchild;
353+
if (new_parent->firstchild != NULL)
354+
new_parent->firstchild->prevchild = context;
357355
new_parent->firstchild = context;
358356
}
359357
else
360358
{
361359
context->parent = NULL;
360+
context->prevchild = NULL;
362361
context->nextchild = NULL;
363362
}
364363
}
@@ -714,6 +713,7 @@ MemoryContextCreate(NodeTag tag, Size size,
714713
node->methods = methods;
715714
node->parent = NULL; /* for the moment */
716715
node->firstchild = NULL;
716+
node->prevchild = NULL;
717717
node->nextchild = NULL;
718718
node->isReset = true;
719719
node->name = ((char *) node) + size;
@@ -728,6 +728,8 @@ MemoryContextCreate(NodeTag tag, Size size,
728728
{
729729
node->parent = parent;
730730
node->nextchild = parent->firstchild;
731+
if (parent->firstchild != NULL)
732+
parent->firstchild->prevchild = node;
731733
parent->firstchild = node;
732734
/* inherit allowInCritSection flag from parent */
733735
node->allowInCritSection = parent->allowInCritSection;

src/include/nodes/memnodes.h

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ typedef struct MemoryContextData
7979
MemoryContextMethods *methods; /* virtual function table */
8080
MemoryContext parent; /* NULL if no parent (toplevel context) */
8181
MemoryContext firstchild; /* head of linked list of children */
82+
MemoryContext prevchild; /* previous child of same parent */
8283
MemoryContext nextchild; /* next child of same parent */
8384
char *name; /* context name (just for debugging) */
8485
MemoryContextCallback *reset_cbs; /* list of reset/delete callbacks */

0 commit comments

Comments
 (0)