From e64c7feb2fd80c89d2220cbe9e026a031f34509c Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 15 Dec 2002 21:01:34 +0000 Subject: [PATCH] Tweak default memory context allocation policy so that a context is not given any malloc block until something is first allocated in it; but thereafter, MemoryContextReset won't release that first malloc block. This preserves the quick-reset property of the original policy, without forcing 8K to be allocated to every context whether any of it is ever used or not. Also, remove some more no-longer-needed explicit freeing during ExecEndPlan. --- src/backend/commands/prepare.c | 8 +++---- src/backend/commands/trigger.c | 13 ++++------- src/backend/executor/execJunk.c | 36 +----------------------------- src/backend/executor/execMain.c | 23 +++++++------------ src/backend/executor/spi.c | 8 +++---- src/backend/utils/cache/relcache.c | 20 ++++++++--------- src/backend/utils/mmgr/aset.c | 26 ++++++++++++++++----- src/backend/utils/mmgr/mcxt.c | 4 ++-- src/include/executor/executor.h | 3 +-- src/include/nodes/execnodes.h | 12 +--------- src/include/utils/memutils.h | 12 ++++++++-- 11 files changed, 66 insertions(+), 99 deletions(-) diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c index ece9802dc4..19d64c3e1c 100644 --- a/src/backend/commands/prepare.c +++ b/src/backend/commands/prepare.c @@ -6,7 +6,7 @@ * Copyright (c) 2002, PostgreSQL Global Development Group * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/prepare.c,v 1.11 2002/12/15 16:17:42 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/prepare.c,v 1.12 2002/12/15 21:01:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -256,9 +256,9 @@ StoreQuery(const char *stmt_name, List *query_list, List *plan_list, /* Make a permanent memory context for the hashtable entry */ entrycxt = AllocSetContextCreate(TopMemoryContext, stmt_name, - 1024, - 1024, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_SMALL_MINSIZE, + ALLOCSET_SMALL_INITSIZE, + ALLOCSET_SMALL_MAXSIZE); oldcxt = MemoryContextSwitchTo(entrycxt); diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 921a11f84c..3dceb548e2 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.141 2002/11/25 03:36:50 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.142 2002/12/15 21:01:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -2008,13 +2008,9 @@ deferredTriggerInvokeEvents(bool immediate_only) void DeferredTriggerInit(void) { - /* - * Since this context will never be reset, give it a minsize of 0. - * This avoids using any memory if the session never stores anything. - */ deftrig_gcxt = AllocSetContextCreate(TopMemoryContext, "DeferredTriggerSession", - 0, + ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); } @@ -2041,12 +2037,11 @@ DeferredTriggerBeginXact(void) /* * Create the per transaction memory context and copy all states from - * the per session context to here. Set the minsize to 0 to avoid - * wasting memory if there is no deferred trigger data. + * the per session context to here. */ deftrig_cxt = AllocSetContextCreate(TopTransactionContext, "DeferredTriggerXact", - 0, + ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); oldcxt = MemoryContextSwitchTo(deftrig_cxt); diff --git a/src/backend/executor/execJunk.c b/src/backend/executor/execJunk.c index edaf7aa40c..0f8b82d4f4 100644 --- a/src/backend/executor/execJunk.c +++ b/src/backend/executor/execJunk.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execJunk.c,v 1.33 2002/12/12 15:49:28 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execJunk.c,v 1.34 2002/12/15 21:01:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -63,8 +63,6 @@ JunkFilter * ExecInitJunkFilter(List *targetList, TupleDesc tupType, TupleTableSlot *slot) { - MemoryContext oldContext; - MemoryContext junkContext; JunkFilter *junkfilter; List *cleanTargetList; int len, @@ -79,19 +77,6 @@ ExecInitJunkFilter(List *targetList, TupleDesc tupType, AttrNumber *cleanMap; Expr *expr; - /* - * Make a memory context that will hold the JunkFilter as well as all - * the subsidiary structures we are about to create. We use smaller- - * than-default sizing parameters since we don't expect a very large - * volume of stuff here. - */ - junkContext = AllocSetContextCreate(CurrentMemoryContext, - "JunkFilterContext", - 1024, - 1024, - ALLOCSET_DEFAULT_MAXSIZE); - oldContext = MemoryContextSwitchTo(junkContext); - /* * First find the "clean" target list, i.e. all the entries in the * original target list which have a false 'resjunk' NOTE: make copy @@ -174,33 +159,14 @@ ExecInitJunkFilter(List *targetList, TupleDesc tupType, junkfilter->jf_cleanLength = cleanLength; junkfilter->jf_cleanTupType = cleanTupType; junkfilter->jf_cleanMap = cleanMap; - junkfilter->jf_junkContext = junkContext; junkfilter->jf_resultSlot = slot; if (slot) ExecSetSlotDescriptor(slot, cleanTupType, false); - MemoryContextSwitchTo(oldContext); - return junkfilter; } -/*------------------------------------------------------------------------- - * ExecFreeJunkFilter - * - * Release the data structures created by ExecInitJunkFilter. - *------------------------------------------------------------------------- - */ -void -ExecFreeJunkFilter(JunkFilter *junkfilter) -{ - /* - * Since the junkfilter is inside its own context, we just have to - * delete the context and we're set. - */ - MemoryContextDelete(junkfilter->jf_junkContext); -} - /*------------------------------------------------------------------------- * ExecGetJunkAttribute * diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index a25f2f2e29..f17fbcbb46 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -26,7 +26,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.193 2002/12/15 16:17:45 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.194 2002/12/15 21:01:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -775,6 +775,12 @@ initResultRelInfo(ResultRelInfo *resultRelInfo, * ExecEndPlan * * Cleans up the query plan -- closes files and frees up storage + * + * NOTE: we are no longer very worried about freeing storage per se + * in this code; FreeExecutorState should be guaranteed to release all + * memory that needs to be released. What we are worried about doing + * is closing relations and dropping buffer pins. Thus, for example, + * tuple tables must be cleared or dropped to ensure pins are released. * ---------------------------------------------------------------- */ void @@ -803,7 +809,7 @@ ExecEndPlan(PlanState *planstate, EState *estate) /* * close the result relation(s) if any, but hold locks until xact - * commit. Also clean up junkfilters if present. + * commit. */ resultRelInfo = estate->es_result_relations; for (i = estate->es_num_result_relations; i > 0; i--) @@ -811,9 +817,6 @@ ExecEndPlan(PlanState *planstate, EState *estate) /* Close indices and then the relation itself */ ExecCloseIndices(resultRelInfo); heap_close(resultRelInfo->ri_RelationDesc, NoLock); - /* Delete the junkfilter if any */ - if (resultRelInfo->ri_junkFilter != NULL) - ExecFreeJunkFilter(resultRelInfo->ri_junkFilter); resultRelInfo++; } @@ -823,16 +826,6 @@ ExecEndPlan(PlanState *planstate, EState *estate) if (estate->es_into_relation_descriptor != NULL) heap_close(estate->es_into_relation_descriptor, NoLock); - /* - * There might be a junkfilter without a result relation. - */ - if (estate->es_num_result_relations == 0 && - estate->es_junkFilter != NULL) - { - ExecFreeJunkFilter(estate->es_junkFilter); - estate->es_junkFilter = NULL; - } - /* * close any relations selected FOR UPDATE, again keeping locks */ diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index cde9ab6ff6..f39c481db9 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.80 2002/12/15 16:17:46 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.81 2002/12/15 21:01:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1489,9 +1489,9 @@ _SPI_copy_plan(_SPI_plan *plan, int location) */ plancxt = AllocSetContextCreate(parentcxt, "SPI Plan", - 1024, - 1024, - ALLOCSET_DEFAULT_MAXSIZE); + ALLOCSET_SMALL_MINSIZE, + ALLOCSET_SMALL_INITSIZE, + ALLOCSET_SMALL_MAXSIZE); oldcxt = MemoryContextSwitchTo(plancxt); /* Copy the SPI plan into its own context */ diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 38c2c5016e..87992769e9 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.181 2002/11/15 17:18:49 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.182 2002/12/15 21:01:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -647,9 +647,9 @@ RelationBuildRuleLock(Relation relation) */ rulescxt = AllocSetContextCreate(CacheMemoryContext, RelationGetRelationName(relation), - 0, /* minsize */ - 1024, /* initsize */ - 1024); /* maxsize */ + ALLOCSET_SMALL_MINSIZE, + ALLOCSET_SMALL_INITSIZE, + ALLOCSET_SMALL_MAXSIZE); relation->rd_rulescxt = rulescxt; /* @@ -994,9 +994,9 @@ RelationInitIndexAccessInfo(Relation relation) */ indexcxt = AllocSetContextCreate(CacheMemoryContext, RelationGetRelationName(relation), - 0, /* minsize */ - 512, /* initsize */ - 1024); /* maxsize */ + ALLOCSET_SMALL_MINSIZE, + ALLOCSET_SMALL_INITSIZE, + ALLOCSET_SMALL_MAXSIZE); relation->rd_indexcxt = indexcxt; /* @@ -2851,9 +2851,9 @@ load_relcache_init_file(void) */ indexcxt = AllocSetContextCreate(CacheMemoryContext, RelationGetRelationName(rel), - 0, /* minsize */ - 512, /* initsize */ - 1024); /* maxsize */ + ALLOCSET_SMALL_MINSIZE, + ALLOCSET_SMALL_INITSIZE, + ALLOCSET_SMALL_MAXSIZE); rel->rd_indexcxt = indexcxt; /* next, read the index strategy map */ diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c index bafe9153e8..e210e42049 100644 --- a/src/backend/utils/mmgr/aset.c +++ b/src/backend/utils/mmgr/aset.c @@ -11,7 +11,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.48 2002/09/04 20:31:33 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.49 2002/12/15 21:01:34 tgl Exp $ * * NOTE: * This is a new (Feb. 05, 1999) implementation of the allocation set @@ -371,10 +371,11 @@ AllocSetInit(MemoryContext context) * Frees all memory which is allocated in the given set. * * Actually, this routine has some discretion about what to do. - * It should mark all allocated chunks freed, but it need not - * necessarily give back all the resources the set owns. Our - * actual implementation is that we hang on to any "keeper" - * block specified for the set. + * It should mark all allocated chunks freed, but it need not necessarily + * give back all the resources the set owns. Our actual implementation is + * that we hang onto any "keeper" block specified for the set. In this way, + * we don't thrash malloc() when a context is repeatedly reset after small + * allocations, which is typical behavior for per-tuple contexts. */ static void AllocSetReset(MemoryContext context) @@ -697,6 +698,21 @@ AllocSetAlloc(MemoryContext context, Size size) block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ; block->endptr = ((char *) block) + blksize; + /* + * If this is the first block of the set, make it the "keeper" block. + * Formerly, a keeper block could only be created during context + * creation, but allowing it to happen here lets us have fast reset + * cycling even for contexts created with minContextSize = 0; that + * way we don't have to force space to be allocated in contexts that + * might never need any space. Don't mark an oversize block as + * a keeper, however. + */ + if (set->blocks == NULL && blksize == set->initBlockSize) + { + Assert(set->keeper == NULL); + set->keeper = block; + } + block->next = set->blocks; set->blocks = block; } diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c index 313a6ad56d..9ce0c4ca72 100644 --- a/src/backend/utils/mmgr/mcxt.c +++ b/src/backend/utils/mmgr/mcxt.c @@ -14,7 +14,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.36 2002/11/13 00:37:06 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.37 2002/12/15 21:01:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -80,7 +80,7 @@ MemoryContextInit(void) */ TopMemoryContext = AllocSetContextCreate((MemoryContext) NULL, "TopMemoryContext", - 8 * 1024, + 0, 8 * 1024, 8 * 1024); diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 571f35c64e..31cc210753 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: executor.h,v 1.84 2002/12/15 16:17:54 tgl Exp $ + * $Id: executor.h,v 1.85 2002/12/15 21:01:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -41,7 +41,6 @@ extern bool ExecSupportsMarkRestore(NodeTag plantype); */ extern JunkFilter *ExecInitJunkFilter(List *targetList, TupleDesc tupType, TupleTableSlot *slot); -extern void ExecFreeJunkFilter(JunkFilter *junkfilter); extern bool ExecGetJunkAttribute(JunkFilter *junkfilter, TupleTableSlot *slot, char *attrName, Datum *value, bool *isNull); extern HeapTuple ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot); diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 65c5f23884..b57d7ac58c 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: execnodes.h,v 1.86 2002/12/15 16:17:56 tgl Exp $ + * $Id: execnodes.h,v 1.87 2002/12/15 21:01:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -218,16 +218,7 @@ typedef struct ProjectionInfo * cleanMap: A map with the correspondence between the non-junk * attribute numbers of the "original" tuple and the * attribute numbers of the "clean" tuple. - * junkContext: memory context holding the JunkFilter node and all - * its subsidiary data structures. * resultSlot: tuple slot that can be used to hold cleaned tuple. - * - * NOTE: the original targetList and tupType are passed to ExecInitJunkFilter, - * as is the resultSlot. These items do not belong to the JunkFilter. All - * the other subsidiary structures are created during ExecInitJunkFilter, - * and all of them can be freed by deleting the memory context junkContext. - * This would not be needed if we had a cleaner approach to managing - * query-lifetime data structures... * ---------------- */ typedef struct JunkFilter @@ -240,7 +231,6 @@ typedef struct JunkFilter int jf_cleanLength; TupleDesc jf_cleanTupType; AttrNumber *jf_cleanMap; - MemoryContext jf_junkContext; TupleTableSlot *jf_resultSlot; } JunkFilter; diff --git a/src/include/utils/memutils.h b/src/include/utils/memutils.h index 8529f94822..94578b8fb6 100644 --- a/src/include/utils/memutils.h +++ b/src/include/utils/memutils.h @@ -10,7 +10,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: memutils.h,v 1.48 2002/09/04 20:31:45 momjian Exp $ + * $Id: memutils.h,v 1.49 2002/12/15 21:01:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -116,8 +116,16 @@ extern MemoryContext AllocSetContextCreate(MemoryContext parent, * Recommended default alloc parameters, suitable for "ordinary" contexts * that might hold quite a lot of data. */ -#define ALLOCSET_DEFAULT_MINSIZE (8 * 1024) +#define ALLOCSET_DEFAULT_MINSIZE 0 #define ALLOCSET_DEFAULT_INITSIZE (8 * 1024) #define ALLOCSET_DEFAULT_MAXSIZE (8 * 1024 * 1024) +/* + * Recommended alloc parameters for "small" contexts that are not expected + * to contain much data (for example, a context to contain a query plan). + */ +#define ALLOCSET_SMALL_MINSIZE 0 +#define ALLOCSET_SMALL_INITSIZE (1 * 1024) +#define ALLOCSET_SMALL_MAXSIZE (8 * 1024) + #endif /* MEMUTILS_H */