Re: [HACKERS] aggregation memory leak and fix - Mailing list pgsql-hackers
From | Bruce Momjian |
---|---|
Subject | Re: [HACKERS] aggregation memory leak and fix |
Date | |
Msg-id | 199903240611.BAA01206@candle.pha.pa.us Whole thread Raw |
In response to | aggregation memory leak and fix (Erik Riedel <riedel+@CMU.EDU>) |
Responses |
Re: [HACKERS] aggregation memory leak and fix
|
List | pgsql-hackers |
> -- > -- Query 1 > -- > select l_returnflag, l_linestatus, sum(l_quantity) as sum_qty, > sum(l_extendedprice) as sum_base_price, > sum(l_extendedprice*(1-l_discount)) as sum_disc_price, > sum(l_extendedprice*(1-l_discount)*(1+l_tax)) as sum_charge, > avg(l_quantity) as avg_qty, avg(l_extendedprice) as avg_price, > avg(l_discount) as avg_disc, count(*) as count_order > from lineitem > where l_shipdate <= ('1998-12-01'::datetime - interval '90 day')::date > group by l_returnflag, l_linestatus > order by l_returnflag, l_linestatus; > > > when I run this against 6.4.2, the postgres process grows to upwards of > 1 GB of memory (at which point something overflows and it dumps core) - > I watch it grow through 200 MB, 400 MB, 800 MB, dies somewhere near 1 GB > of allocated memory). > Here is my first attempt at fixing the expression memory leak you mentioned. I have run it through the regression tests, and it seems to be harmless there. I am interested to see if it fixes the expression leak you saw. I have not committed this yet. I want to look at it some more. -- Bruce Momjian | http://www.op.net/~candle maillist@candle.pha.pa.us | (610) 853-3000 + If your life is a hard drive, | 830 Blythe Avenue + Christ can be your backup. | Drexel Hill, Pennsylvania 19026 Index: execQual.c =================================================================== RCS file: /usr/local/cvsroot/pgsql/src/backend/executor/execQual.c,v retrieving revision 1.50 diff -c -r1.50 execQual.c *** execQual.c 1999/03/20 02:07:31 1.50 --- execQual.c 1999/03/24 06:09:25 *************** *** 51,56 **** --- 51,57 ---- #include "utils/fcache2.h" #include "utils/mcxt.h" #include "utils/memutils.h" + #include "utils/portal.h" /* *************** *** 65,70 **** --- 66,74 ---- bool execConstByVal; int execConstLen; + bool allocatedQualContext; + bool allocatedQualNesting; + /* static functions decls */ static Datum ExecEvalAggref(Aggref *aggref, ExprContext *econtext, bool *isNull); static Datum ExecEvalArrayRef(ArrayRef *arrayRef, ExprContext *econtext, *************** *** 801,814 **** else { int i; if (isDone) *isDone = true; for (i = 0; i < fcache->nargs; i++) if (fcache->nullVect[i] == true) *isNull = true; ! return (Datum) fmgr_c(&fcache->func, (FmgrValues *) argV, isNull); } } --- 805,852 ---- else { int i; + Datum d; + char pname[64]; + Portal qual_portal; + MemoryContext oldcxt; if (isDone) *isDone = true; for (i = 0; i < fcache->nargs; i++) if (fcache->nullVect[i] == true) *isNull = true; + + /* + * Assign adt *.c memory in separate context to prevent + * unbounded memory growth in large queries that use functions. + * We clear this memory after the qual has been completed. + * bjm 1999/03/24 + */ + strcpy(pname, "<Qual manager>"); + qual_portal = GetPortalByName(pname); + if (!PortalIsValid(qual_portal)) + { + qual_portal = CreatePortal(pname); + Assert(PortalIsValid(qual_portal)); ! oldcxt = MemoryContextSwitchTo( ! (MemoryContext) PortalGetHeapMemory(qual_portal)); ! StartPortalAllocMode(DefaultAllocMode, 0); ! MemoryContextSwitchTo(oldcxt); ! ! allocatedQualContext = true; ! allocatedQualNesting = 0; ! } ! allocatedQualNesting++; ! ! oldcxt = MemoryContextSwitchTo( ! (MemoryContext) PortalGetHeapMemory(qual_portal)); ! ! d = (Datum) fmgr_c(&fcache->func, (FmgrValues *) argV, isNull); ! ! MemoryContextSwitchTo(oldcxt); ! allocatedQualNesting--; ! return d; } } *************** *** 1354,1359 **** --- 1392,1399 ---- { List *clause; bool result; + char pname[64]; + Portal qual_portal; /* * debugging stuff *************** *** 1387,1396 **** break; } /* * if result is true, then it means a clause failed so we * return false. if result is false then it means no clause ! * failed so we return true. */ if (result == true) return false; --- 1427,1459 ---- break; } + if (allocatedQualContext && allocatedQualNesting == 0) + { + MemoryContext oldcxt; + + strcpy(pname, "<Qual manager>"); + qual_portal = GetPortalByName(pname); + /* + * allocatedQualContext may have been improperly set from + * from a previous run. + */ + if (PortalIsValid(qual_portal)) + { + oldcxt = MemoryContextSwitchTo( + (MemoryContext) PortalGetHeapMemory(qual_portal)); + + EndPortalAllocMode(); + StartPortalAllocMode(DefaultAllocMode, 0); + + MemoryContextSwitchTo(oldcxt); + } + allocatedQualContext = false; + } + /* * if result is true, then it means a clause failed so we * return false. if result is false then it means no clause ! * failed so we return true. ...Yikes, who wrote that? */ if (result == true) return false;
pgsql-hackers by date: