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

Commit b0025bd

Browse files
committed
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.
1 parent 5f42e59 commit b0025bd

File tree

2 files changed

+65
-19
lines changed

2 files changed

+65
-19
lines changed

src/backend/utils/mmgr/mcxt.c

Lines changed: 63 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -178,26 +178,8 @@ MemoryContextDelete(MemoryContext context)
178178
* there's an error we won't have deleted/busted contexts still attached
179179
* to the context tree. Better a leak than a crash.
180180
*/
181-
if (context->parent)
182-
{
183-
MemoryContext parent = context->parent;
184-
185-
if (context == parent->firstchild)
186-
parent->firstchild = context->nextchild;
187-
else
188-
{
189-
MemoryContext child;
181+
MemoryContextSetParent(context, NULL);
190182

191-
for (child = parent->firstchild; child; child = child->nextchild)
192-
{
193-
if (context == child->nextchild)
194-
{
195-
child->nextchild = context->nextchild;
196-
break;
197-
}
198-
}
199-
}
200-
}
201183
(*context->methods->delete_context) (context);
202184
pfree(context);
203185
}
@@ -237,6 +219,67 @@ MemoryContextResetAndDeleteChildren(MemoryContext context)
237219
MemoryContextReset(context);
238220
}
239221

222+
/*
223+
* MemoryContextSetParent
224+
* Change a context to belong to a new parent (or no parent).
225+
*
226+
* We provide this as an API function because it is sometimes useful to
227+
* change a context's lifespan after creation. For example, a context
228+
* might be created underneath a transient context, filled with data,
229+
* and then reparented underneath CacheMemoryContext to make it long-lived.
230+
* In this way no special effort is needed to get rid of the context in case
231+
* a failure occurs before its contents are completely set up.
232+
*
233+
* Callers often assume that this function cannot fail, so don't put any
234+
* elog(ERROR) calls in it.
235+
*
236+
* A possible caller error is to reparent a context under itself, creating
237+
* a loop in the context graph. We assert here that context != new_parent,
238+
* but checking for multi-level loops seems more trouble than it's worth.
239+
*/
240+
void
241+
MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
242+
{
243+
AssertArg(MemoryContextIsValid(context));
244+
AssertArg(context != new_parent);
245+
246+
/* Delink from existing parent, if any */
247+
if (context->parent)
248+
{
249+
MemoryContext parent = context->parent;
250+
251+
if (context == parent->firstchild)
252+
parent->firstchild = context->nextchild;
253+
else
254+
{
255+
MemoryContext child;
256+
257+
for (child = parent->firstchild; child; child = child->nextchild)
258+
{
259+
if (context == child->nextchild)
260+
{
261+
child->nextchild = context->nextchild;
262+
break;
263+
}
264+
}
265+
}
266+
}
267+
268+
/* And relink */
269+
if (new_parent)
270+
{
271+
AssertArg(MemoryContextIsValid(new_parent));
272+
context->parent = new_parent;
273+
context->nextchild = new_parent->firstchild;
274+
new_parent->firstchild = context;
275+
}
276+
else
277+
{
278+
context->parent = NULL;
279+
context->nextchild = NULL;
280+
}
281+
}
282+
240283
/*
241284
* GetMemoryChunkSpace
242285
* Given a currently-allocated chunk, determine the total space
@@ -489,6 +532,7 @@ MemoryContextCreate(NodeTag tag, Size size,
489532
(*node->methods->init) (node);
490533

491534
/* OK to link node to parent (if any) */
535+
/* Could use MemoryContextSetParent here, but doesn't seem worthwhile */
492536
if (parent)
493537
{
494538
node->parent = parent;

src/include/utils/memutils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ extern void MemoryContextDelete(MemoryContext context);
9090
extern void MemoryContextResetChildren(MemoryContext context);
9191
extern void MemoryContextDeleteChildren(MemoryContext context);
9292
extern void MemoryContextResetAndDeleteChildren(MemoryContext context);
93+
extern void MemoryContextSetParent(MemoryContext context,
94+
MemoryContext new_parent);
9395
extern Size GetMemoryChunkSpace(void *pointer);
9496
extern MemoryContext GetMemoryChunkContext(void *pointer);
9597
extern bool MemoryContextIsEmpty(MemoryContext context);

0 commit comments

Comments
 (0)