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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy