memory-context-delete-with-fixed-stack-space.patch
text/x-diff
Filename: memory-context-delete-with-fixed-stack-space.patch
Type: text/x-diff
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| src/backend/utils/mmgr/mcxt.c | 27 | 4 |
diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c
index 41f2390fb8..7cc220bca0 100644
--- a/src/backend/utils/mmgr/mcxt.c
+++ b/src/backend/utils/mmgr/mcxt.c
@@ -447,14 +447,37 @@ MemoryContextDelete(MemoryContext context)
void
MemoryContextDeleteChildren(MemoryContext context)
{
+ MemoryContext cur,
+ next;
+
Assert(MemoryContextIsValid(context));
/*
- * MemoryContextDelete will delink the child from me, so just iterate as
- * long as there is a child.
+ * We iterate rather than recursing, so that cleaning up a deep nest of
+ * contexts doesn't require unbounded stack space. (This avoids possible
+ * failure during transaction cleanup, which would be bad.) This works
+ * because by the time we traverse back up to a parent context, it will
+ * have no remaining children and will be seen as deletable.
*/
- while (context->firstchild != NULL)
- MemoryContextDelete(context->firstchild);
+ cur = context->firstchild;
+ while (cur != NULL)
+ {
+ /* Descend until we find a childless context */
+ if (cur->firstchild != NULL)
+ {
+ cur = cur->firstchild;
+ continue;
+ }
+ /* We can delete cur, but first remember the next deletion target */
+ if (cur->nextchild != NULL)
+ next = cur->nextchild;
+ else if (cur->parent != context)
+ next = cur->parent;
+ else
+ next = NULL;
+ MemoryContextDelete(cur);
+ cur = next;
+ }
}
/*