Tweak default memory context allocation policy so that a context is not
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 15 Dec 2002 21:01:34 +0000 (21:01 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 15 Dec 2002 21:01:34 +0000 (21:01 +0000)
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
src/backend/commands/trigger.c
src/backend/executor/execJunk.c
src/backend/executor/execMain.c
src/backend/executor/spi.c
src/backend/utils/cache/relcache.c
src/backend/utils/mmgr/aset.c
src/backend/utils/mmgr/mcxt.c
src/include/executor/executor.h
src/include/nodes/execnodes.h
src/include/utils/memutils.h

index ece9802dc41d7837bc2c24c0023d838d357ec17c..19d64c3e1c74ec8a6491f2ba780bd076860bcf6f 100644 (file)
@@ -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);
 
index 921a11f84c6a9e6f3c890734a07797bf704f41c0..3dceb548e2144afa7edda80590cb10ddb0c53bb2 100644 (file)
@@ -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);
index edaf7aa40cd511c0ae12586b124559742533a249..0f8b82d4f472f91eb0e5f7cb545e2a887e3c6b46 100644 (file)
@@ -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
  *
index a25f2f2e296b41866f7bc7315622f1365f55903e..f17fbcbb4661b7e89ec2cf8a29799f867734d93e 100644 (file)
@@ -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
     */
index cde9ab6ff6ee2f2cdd79093baa152a9a7e467a36..f39c481db9310940cdad1b3a24abc42d960693d7 100644 (file)
@@ -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 */
index 38c2c5016ef715f6f67607d81d512dc8141ea3e6..87992769e99a8a41c6e2ca6aac826032e94dc304 100644 (file)
@@ -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 */
index bafe9153e8243ac4888d2461cb860338c7c5a775..e210e42049a4dc2a1cc421ee373240d8eeacb219 100644 (file)
@@ -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;
    }
index 313a6ad56dd98c8f7650b890a6ed5c52be46ebd4..9ce0c4ca72fed8742b1230aa6a164f98ad7e56d2 100644 (file)
@@ -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);
 
index 571f35c64e3ae9fa5c91a391d8bd71817625944f..31cc2107536aa7a096ef948ae4bf3e29f186d248 100644 (file)
@@ -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);
index 65c5f23884dca2476a4876351cb73f003144997c..b57d7ac58ccd6b46a3191e311e9134dada0fec1a 100644 (file)
@@ -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;
 
index 8529f948227b8eeb91da11baa51ad4088bd988b3..94578b8fb6fbf42ad68d658f4d47b3743ce3b55a 100644 (file)
@@ -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 */