Thread: Progress report: intraquery memory recovery in executor
My original idea for using the new "memory context" mechanisms for recovering memory in the executor went like this: in each Plan node, create a "per tuple" context that would be reset at the start of each ExecProcNode call, thereby recovering memory allocated in the previous tuple cycle. I envisioned resetting and switching into this context at the start of each call of the node's ExecProcNode routine. This idea has pretty much crashed and burned on takeoff :-(. It turns out there are way too many plan-level routines that assume they can do palloc() to allocate memory that will still be there the next time they are called. An example is that rtree index scans use a stack of palloc'd nodes to keep track of where they are ... and that stack had better still be there when you ask for the next tuple. We could possibly teach all these places to use something other than CurrentMemoryContext for their allocations, but it doesn't look like an appetizing prospect. It looks tedious and highly error-prone, both of which are adjectives I'd hoped to avoid for this project. What I'm currently considering instead is to still create a per-tuple context for each plan node, but use it only for expression evaluation, ie, we switch into it on entry to ExecQual(), ExecTargetList(), ExecProject(), maybe a few other places. The majority of our leakage problems are associated with expression evaluation, so this should allow fixing the leakage problems. It will mean that routines associated with plan nodes (basically, executor/node*.c) will still need to be careful to avoid leaks. For the most part they are already, but I had hoped to make that care less necessary. Comments, better ideas? regards, tom lane
At 02:31 10/07/00 -0400, Tom Lane wrote: > >What I'm currently considering instead is to still create a per-tuple >context for each plan node, but use it only for expression evaluation, >ie, we switch into it on entry to ExecQual(), ExecTargetList(), >ExecProject(), maybe a few other places. The majority of our leakage >problems are associated with expression evaluation, so this should allow >fixing the leakage problems. It will mean that routines associated with >plan nodes (basically, executor/node*.c) will still need to be careful >to avoid leaks. For the most part they are already, but I had hoped to >make that care less necessary. > Is it simple for the person writing the low level routines to choose (easily) to allocate 'temporary' memory vs. 'permanent' memory? If some mechanism were in place for this, then the code could slowly be migrated...at least reducing the tedium. ---------------------------------------------------------------- Philip Warner | __---_____ Albatross Consulting Pty. Ltd. |----/ - \ (A.C.N. 008 659 498) | /(@) ______---_ Tel: (+61) 0500 83 82 81 | _________ \ Fax: (+61) 0500 83 82 82 | ___________ | Http://www.rhyme.com.au | / \| | --________-- PGP key available upon request, | / and from pgp5.ai.mit.edu:11371 |/
> What I'm currently considering instead is to still create a per-tuple > context for each plan node, but use it only for expression evaluation, > ie, we switch into it on entry to ExecQual(), ExecTargetList(), > ExecProject(), maybe a few other places. The majority of our leakage > problems are associated with expression evaluation, so this should allow > fixing the leakage problems. It will mean that routines associated with > plan nodes (basically, executor/node*.c) will still need to be careful > to avoid leaks. For the most part they are already, but I had hoped to > make that care less necessary. I was wondering how you were going to pull this off. It seems doing something on entry to the expression routines is best. -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 853-3000+ If your life is a hard drive, | 830 Blythe Avenue + Christ can be your backup. | Drexel Hill, Pennsylvania19026
Philip Warner <pjw@rhyme.com.au> writes: > Is it simple for the person writing the low level routines to choose > (easily) to allocate 'temporary' memory vs. 'permanent' memory? One of the main problems is that a low-level routine doesn't necessarily know which is appropriate --- the answer may vary depending on where it was called from. To do it that way, I think we'd end up decorating a large number of internal APIs with extra MemoryContext arguments. (This is exactly why we have a global CurrentMemoryContext in the first place...) That's why I wanted to do the management at the level of the Plan node executor routines, which are high-level enough that they have some clue what's going on. regards, tom lane
At 10:08 10/07/00 -0400, Tom Lane wrote: >Philip Warner <pjw@rhyme.com.au> writes: >> Is it simple for the person writing the low level routines to choose >> (easily) to allocate 'temporary' memory vs. 'permanent' memory? > >One of the main problems is that a low-level routine doesn't necessarily >know which is appropriate --- the answer may vary depending on where it >was called from. ... >That's why I wanted to do the management at the level of the Plan node >executor routines, which are high-level enough that they have some clue >what's going on. ISTM (with, perhaps, no basis (ISTMWPNB?)) that when allocating memory there are a couple of cases: You want it to be available: 1. until the end of the current call 2. at least until the next call 3. until TX end 4. forever ...etc. If there are still cases where the called routine can't tell what sort of memory it wants, then my method won't work (and I'd be interested to know what they are). But if a relatively short list of allocation types can be created, then the palloc replacement can be passed an extra parameter (the 'allocation type'), and handle memory contexts appropriately. Feel free to tell me if this is so way off the mark that there is no purpose in pursuing the discussion... ---------------------------------------------------------------- Philip Warner | __---_____ Albatross Consulting Pty. Ltd. |----/ - \ (A.C.N. 008 659 498) | /(@) ______---_ Tel: (+61) 0500 83 82 81 | _________ \ Fax: (+61) 0500 83 82 82 | ___________ | Http://www.rhyme.com.au | / \| | --________-- PGP key available upon request, | / and from pgp5.ai.mit.edu:11371 |/
Bruce Momjian <pgman@candle.pha.pa.us> writes: > I was wondering how you were going to pull this off. It seems doing > something on entry to the expression routines is best. Yeah, associating a short-term memory context with each ExprContext is looking like the way to proceed. regards, tom lane
Philip Warner <pjw@rhyme.com.au> writes: > ISTM (with, perhaps, no basis (ISTMWPNB?)) that when allocating memory > there are a couple of cases: > You want it to be available: > 1. until the end of the current call > 2. at least until the next call > 3. until TX end > 4. forever > ...etc. Right, that's essentially what the various MemoryContexts are for. > But if a relatively short list of allocation types can be created, then the > palloc replacement can be passed an extra parameter (the 'allocation > type'), and handle memory contexts appropriately. I don't think that's a superior solution to passing a target MemoryContext around. An allocation-type parameter would just mean an extra lookup in some global array to find the appropriate MemoryContext. That means even more global state, rather than less, and it's not as extensible. Right now, if you have a need for a context with some weird lifetime, you just make one and then delete it again later --- the knowledge of the context's very existence, as well as lifetime, is localized. In an allocation-type world you'd need to either add a new allocation type code or figure out which existing category to force-fit your context into. In any case, this doesn't address the real practical problem, which is going around and changing hundreds of routines and thousands of calls thereto... I really *don't* want to add a memory management parameter to everything in sight. Doesn't matter how the parameter is defined. regards, tom lane