]> granicus.if.org Git - postgresql/commitdiff
Redefine MemoryContextReset() as deleting, not resetting, child contexts.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 27 Feb 2015 23:09:42 +0000 (18:09 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 27 Feb 2015 23:10:04 +0000 (18:10 -0500)
That is, MemoryContextReset() now means what was formerly meant by
MemoryContextResetAndDeleteChildren(), and the latter is now just a macro
alias for the former.  If you really want the functionality that was
formerly provided by MemoryContextReset(), what you have to do is
MemoryContextResetChildren() plus MemoryContextResetOnly() (which is a
new API to reset *only* the named context and not touch its children).

The reason for this change is that near fifteen years of experience has
proven that there is noplace where old-style MemoryContextReset() is
actually what you want.  Making that the default behavior has led to lots
of context-leakage bugs, while we've not found anyplace where it's actually
necessary to keep the child contexts; at least the standard regression
tests do not reveal anyplace where this change breaks anything.  And there
are upcoming patches that will introduce additional reasons why child
contexts need to be removed.

We could change existing calls of MemoryContextResetAndDeleteChildren to be
just MemoryContextReset, but for the moment I'll leave them alone; they're
not costing anything.

src/backend/utils/mmgr/README
src/backend/utils/mmgr/mcxt.c
src/include/utils/memutils.h

index 45e610dd061f01fbc9f94222c0857da23da0076f..4ebb78e4eb046a611f3eb74de5b7e76a86058d90 100644 (file)
@@ -125,9 +125,14 @@ lifetimes that only partially overlap can be handled by allocating
 from different trees of the context forest (there are some examples
 in the next section).
 
-For convenience we will also want operations like "reset/delete all
-children of a given context, but don't reset or delete that context
-itself".
+Actually, it turns out that resetting a given context should almost
+always imply deleting (not just resetting) any child contexts it has.
+So MemoryContextReset() means that, and if you really do want a tree of
+empty contexts you need to call MemoryContextResetOnly() plus
+MemoryContextResetChildren().
+
+For convenience we also provide operations like "reset/delete all children
+of a given context, but don't reset or delete that context itself".
 
 
 Globally Known Contexts
index 72a32abdddb671769d8999a3f30b009ea603b900..e2fbfd420b661bdcc88b9bcb023414425fb46b8c 100644 (file)
@@ -132,11 +132,8 @@ MemoryContextInit(void)
 
 /*
  * MemoryContextReset
- *             Release all space allocated within a context and its descendants,
- *             but don't delete the contexts themselves.
- *
- * The type-specific reset routine handles the context itself, but we
- * have to do the recursion for the children.
+ *             Release all space allocated within a context and delete all its
+ *             descendant contexts (but not the named context itself).
  */
 void
 MemoryContextReset(MemoryContext context)
@@ -145,7 +142,22 @@ MemoryContextReset(MemoryContext context)
 
        /* save a function call in common case where there are no children */
        if (context->firstchild != NULL)
-               MemoryContextResetChildren(context);
+               MemoryContextDeleteChildren(context);
+
+       /* save a function call if no pallocs since startup or last reset */
+       if (!context->isReset)
+               MemoryContextResetOnly(context);
+}
+
+/*
+ * MemoryContextResetOnly
+ *             Release all space allocated within a context.
+ *             Nothing is done to the context's descendant contexts.
+ */
+void
+MemoryContextResetOnly(MemoryContext context)
+{
+       AssertArg(MemoryContextIsValid(context));
 
        /* Nothing to do if no pallocs since startup or last reset */
        if (!context->isReset)
@@ -172,7 +184,10 @@ MemoryContextResetChildren(MemoryContext context)
        AssertArg(MemoryContextIsValid(context));
 
        for (child = context->firstchild; child != NULL; child = child->nextchild)
-               MemoryContextReset(child);
+       {
+               MemoryContextResetChildren(child);
+               MemoryContextResetOnly(child);
+       }
 }
 
 /*
@@ -234,23 +249,6 @@ MemoryContextDeleteChildren(MemoryContext context)
                MemoryContextDelete(context->firstchild);
 }
 
-/*
- * MemoryContextResetAndDeleteChildren
- *             Release all space allocated within a context and delete all
- *             its descendants.
- *
- * This is a common combination case where we want to preserve the
- * specific context but get rid of absolutely everything under it.
- */
-void
-MemoryContextResetAndDeleteChildren(MemoryContext context)
-{
-       AssertArg(MemoryContextIsValid(context));
-
-       MemoryContextDeleteChildren(context);
-       MemoryContextReset(context);
-}
-
 /*
  * MemoryContextRegisterResetCallback
  *             Register a function to be called before next context reset/delete.
index 76ad7d443b03053f4637467e72d2f1bb1fc4f26a..dbb163a15364cb79254d9f43d68531b17edabf36 100644 (file)
@@ -84,6 +84,9 @@ extern PGDLLIMPORT MemoryContext CurTransactionContext;
 /* This is a transient link to the active portal's memory context: */
 extern PGDLLIMPORT MemoryContext PortalContext;
 
+/* Backwards compatibility macro */
+#define MemoryContextResetAndDeleteChildren(ctx) MemoryContextReset(ctx)
+
 
 /*
  * Memory-context-type-independent functions in mcxt.c
@@ -91,9 +94,9 @@ extern PGDLLIMPORT MemoryContext PortalContext;
 extern void MemoryContextInit(void);
 extern void MemoryContextReset(MemoryContext context);
 extern void MemoryContextDelete(MemoryContext context);
+extern void MemoryContextResetOnly(MemoryContext context);
 extern void MemoryContextResetChildren(MemoryContext context);
 extern void MemoryContextDeleteChildren(MemoryContext context);
-extern void MemoryContextResetAndDeleteChildren(MemoryContext context);
 extern void MemoryContextRegisterResetCallback(MemoryContext context,
                                                                   MemoryContextCallback *cb);
 extern void MemoryContextSetParent(MemoryContext context,